Détection du langage de programmation à partir d'un extrait

115

Quelle serait la meilleure façon de détecter le langage de programmation utilisé dans un extrait de code?

João Matos
la source
1
Il existe pratiquement un nombre infini de langues ... voulez-vous en détecter UNE? Ou parlons-nous simplement des plus populaires?
Spencer Ruport
Juste les plus populaires (C / C ++, C #, Java, Pascal, Python, VB.NET. PHP, JavaScript et peut-être Haskell).
João Matos
12
Eh bien, Haskell ne peut pas être populaire puisque je n'en ai jamais entendu parler. ;-)
Stephanie Page
22
Vous ne savez probablement pas grand-chose sur les langages de programmation si vous n'avez pas entendu parler de Haskell.
Akhorus
4
Il y a ce service en ligne qui le fait: algorithmia.com/algorithms/PetiteProgrammer/...
Benny Neugebauer

Réponses:

99

Je pense que la méthode utilisée dans les filtres anti-spam fonctionnerait très bien. Vous divisez l'extrait en mots. Ensuite, vous comparez les occurrences de ces mots avec des extraits connus et calculez la probabilité que cet extrait soit écrit dans la langue X pour chaque langue qui vous intéresse.

http://en.wikipedia.org/wiki/Bayesian_spam_filtering

Si vous avez le mécanisme de base, alors il est très facile d'ajouter de nouvelles langues: il suffit de former le détecteur avec quelques extraits de code dans la nouvelle langue (vous pouvez le nourrir d'un projet open source). De cette façon, il apprend que "System" est susceptible d'apparaître dans les extraits de code C # et de "met" dans les extraits de code Ruby.

J'ai en fait utilisé cette méthode pour ajouter une détection de langue aux extraits de code pour les logiciels de forum. Cela a fonctionné 100% du temps, sauf dans des cas ambigus:

print "Hello"

Laissez-moi trouver le code.

Je n'ai pas trouvé le code alors j'en ai créé un nouveau. C'est un peu simpliste mais ça marche pour mes tests. Actuellement, si vous lui donnez beaucoup plus de code Python que de code Ruby, il est probable que ce code:

def foo
   puts "hi"
end

est du code Python (bien que ce soit vraiment Ruby). C'est parce que Python a aussi un defmot - clé. Donc, s'il a vu 1000x defen Python et 100x defen Ruby, il peut toujours dire Python même si putset endest spécifique à Ruby. Vous pouvez résoudre ce problème en gardant une trace des mots vus par langue et en les divisant par cela quelque part (ou en lui fournissant des quantités égales de code dans chaque langue).

J'espère que ça t'aide:

class Classifier
  def initialize
    @data = {}
    @totals = Hash.new(1)
  end

  def words(code)
    code.split(/[^a-z]/).reject{|w| w.empty?}
  end

  def train(code,lang)
    @totals[lang] += 1
    @data[lang] ||= Hash.new(1)
    words(code).each {|w| @data[lang][w] += 1 }
  end

  def classify(code)
    ws = words(code)
    @data.keys.max_by do |lang|
      # We really want to multiply here but I use logs 
      # to avoid floating point underflow
      # (adding logs is equivalent to multiplication)
      Math.log(@totals[lang]) +
      ws.map{|w| Math.log(@data[lang][w])}.reduce(:+)
    end
  end
end

# Example usage

c = Classifier.new

# Train from files
c.train(open("code.rb").read, :ruby)
c.train(open("code.py").read, :python)
c.train(open("code.cs").read, :csharp)

# Test it on another file
c.classify(open("code2.py").read) # => :python (hopefully)
Jules
la source
1
J'ai également besoin de l'utiliser dans un logiciel de forum. Merci pour le conseil sur le filtrage bayésien.
João Matos
12
J'ai fait quelque chose comme ça dans mon cours de PNL, mais nous l'avons fait un peu plus loin. Vous n'aimez pas regarder les fréquences d'un seul mot, mais des paires et des triplets de mots. Par exemple, "public" peut être un mot clé dans de nombreux langages, mais "public static void" est plus courant en C #. Si le triple ne peut être trouvé, vous revenez à 2, puis à 1.
mpen
1
Vous voudrez peut-être aussi réfléchir à l'endroit où vous divisez les mots. En PHP, les variables commencent par $, alors peut-être que vous ne devriez pas vous séparer sur des limites de mots, car le $devrait rester avec la variable. Les opérateurs aiment =>et :=devraient être collés ensemble comme un seul jeton, mais OTH vous devriez probablement vous séparer autour de {s car ils sont toujours autonomes.
mpen
2
Oui. Un moyen d'éviter le fractionnement du tout est d'utiliser des ngrams: vous prenez toutes les n sous-chaînes de longueur. Par exemple, les 5 grammes de "met foo" sont "met", "uts f", "ts fo" et "s foo". Cette stratégie peut sembler étrange mais elle fonctionne mieux que vous ne le pensez, ce n'est tout simplement pas la façon dont un humain résoudrait le problème. Pour décider quelle méthode fonctionne le mieux, vous devrez tester les deux ...
Jules
2
Certaines langues ont cependant très peu de syntaxe. Je spécule également que les noms de variables communs domineraient sur les mots-clés de la langue. Fondamentalement, si vous avez un morceau de code C écrit par un hongrois, avec des noms de variables et des commentaires en hongrois, dans vos données de formation, alors toute autre source contenant du hongrois est susceptible d'être considérée comme "similaire".
tripleee
26

Détection de la langue résolue par d'autres:

L'approche d'Ohloh: https://github.com/blackducksw/ohcount/

L'approche de Github: https://github.com/github/linguist

nisc
la source
4
J'ai examiné ces deux solutions et aucune ne fera exactement ce qui a été demandé. Ils regardent principalement les extensions de fichiers pour déterminer la langue, ils ne peuvent donc pas nécessairement examiner un extrait de code sans un indice de l'extension.
Hawkee
5
L'approche de Github inclut désormais également un classificateur bayésien. Il détecte principalement un candidat de langue basé sur l'extension de fichier, mais lorsqu'une extension de fichier correspond à plusieurs candidats (par exemple ".h" -> C, C ++, ObjC), il tokenize l'échantillon de code d'entrée et le classifie par rapport à un ensemble pré-entraîné de données. La version Github peut être forcée de toujours scanner le code sans regarder l'extension.
Benzi
7

Guesslang est une solution possible:

http://guesslang.readthedocs.io/en/latest/index.html

Il y a aussi SourceClassifier:

https://github.com/chrislo/sourceclassifier/tree/master

Je me suis intéressé à ce problème après avoir trouvé du code dans un article de blog que je n'ai pas pu identifier. Ajout de cette réponse puisque cette question était le premier résultat de recherche pour "identifier le langage de programmation".

ElectricWarr
la source
5

C'est très difficile et parfois impossible. De quelle langue provient ce court extrait?

int i = 5;
int k = 0;
for (int j = 100 ; j > i ; i++) {
    j = j + 1000 / i;
    k = k + i * j;
}

(Indice: il peut s'agir de n'importe lequel d'entre eux.)

Vous pouvez essayer d'analyser différentes langues et essayer de décider en utilisant l'analyse de fréquence des mots-clés. Si certains ensembles de mots-clés se produisent avec certaines fréquences dans un texte, il est probable que le langage soit Java, etc. comme mot-clé en Java, et l'analyse de fréquence sera trompée.

Si vous augmentez d'un cran la complexité, vous pouvez rechercher des structures, si un certain mot-clé vient toujours après un autre, cela vous donnera plus d'indices. Mais il sera également beaucoup plus difficile à concevoir et à mettre en œuvre.


la source
26
Eh bien, si plusieurs langues sont possibles, le détecteur peut simplement donner tous les candidats possibles.
Steven Haryanto
Ou, il peut donner le premier qui correspond. Si le cas d'utilisation dans le monde réel est quelque chose comme la coloration syntaxique, cela ne ferait vraiment aucune différence. Cela signifie que l'une des langues correspondantes entraînerait la mise en évidence du code correctement.
jonschlinkert
5

Une alternative consiste à utiliser highlight.js , qui effectue la coloration syntaxique mais utilise le taux de réussite du processus de mise en évidence pour identifier la langue. En principe, n'importe quelle base de code de surligneur de syntaxe peut être utilisée de la même manière, mais la bonne chose à propos de highlight.js est que la détection de la langue est considérée comme une fonctionnalité et est utilisée à des fins de test .

MISE À JOUR: J'ai essayé ceci et cela n'a pas très bien fonctionné. Le JavaScript compressé l'a complètement confondu, c'est-à-dire que le tokenizer est sensible aux espaces. En règle générale, il ne semble pas très fiable de compter uniquement les hits de faits saillants. Un analyseur plus puissant, ou peut-être un nombre de sections inégalé, pourrait mieux fonctionner.

Andy Jackson
la source
Les données de langue incluses dans highlight.js sont limitées aux valeurs nécessaires pour la mise en évidence, ce qui s'avère assez insuffisant pour la détection de la langue (en particulier pour de petites quantités de code).
Adam Kennedy
Je pense que ça va, vérifiez avec ce violon jsfiddle.net/3tgjnz10
sebilasse
4

Tout d'abord, j'essaierais de trouver les keyworks spécifiques d'une langue, par exemple

"package, class, implements "=> JAVA
"<?php " => PHP
"include main fopen strcmp stdout "=>C
"cout"=> C++
etc...
Pierre
la source
3
Le problème est que ces mots-clés peuvent toujours apparaître dans n'importe quelle langue, que ce soit sous forme de noms de variables ou de chaînes. Cela, et il y a beaucoup de chevauchement dans les mots clés utilisés. Vous devrez faire plus que simplement rechercher des mots clés.
mpen
2

Cela dépendrait du type d'extrait de code que vous avez, mais je le ferais passer par une série de tokenizers et verrais dans quelle langue le BNF est valide.

Oui - ce Jake.
la source
Toutes les langues ne peuvent même pas être décrites par un BNF. Si vous êtes autorisé à redéfinir des mots-clés et à créer des macros, cela devient beaucoup plus difficile. Alså, car nous parlons d'un extrait de code, vous devrez faire une correspondance partielle contre un BNF, ce qui est plus difficile et plus sujet aux erreurs.
2

Joli puzzle.

Je pense qu'il est impossible de détecter toutes les langues. Mais vous pouvez déclencher sur des jetons clés. (certains mots réservés et combinaisons de caractères souvent utilisées).

Ben il y a beaucoup de langages avec une syntaxe similaire. Cela dépend donc de la taille de l'extrait.

Toon Krijthe
la source
1

Prettify est un package Javascript qui détecte correctement les langages de programmation:

http://code.google.com/p/google-code-prettify/

Il s'agit principalement d'un surligneur de syntaxe, mais il existe probablement un moyen d'extraire la partie de détection afin de détecter la langue à partir d'un extrait de code.

Hawkee
la source
1
Après une inspection plus approfondie, il semble que Prettify ne détecte pas réellement la langue, mais il met en évidence en fonction de la syntaxe de chaque élément.
Hawkee
1

J'en avais besoin alors j'ai créé le mien. https://github.com/bertyhell/CodeClassifier

Il est très facilement extensible en ajoutant un fichier de formation dans le bon dossier. Écrit en c #. Mais j'imagine que le code est facilement converti dans n'importe quelle autre langue.

Berty
la source
0

Je ne pense pas qu'il y aurait un moyen facile d'accomplir cela. Je générerais probablement des listes de symboles / mots-clés communs uniques à certaines langues / classes de langues (par exemple, les accolades pour le langage de style C, les mots-clés Dim et Sub pour les langages BASIC, le mot-clé def pour Python, le mot-clé let pour les langages fonctionnels) . Vous pourrez alors peut-être utiliser les fonctionnalités de syntaxe de base pour le réduire encore plus.

Noldorin
la source
0

Je pense que la plus grande distinction entre les langues est sa structure. Mon idée serait donc d'examiner certains éléments communs dans toutes les langues et de voir en quoi ils diffèrent. Par exemple, vous pouvez utiliser des expressions régulières pour sélectionner des éléments tels que:

  • définitions de fonction
  • déclarations de variables
  • déclarations de classe
  • commentaires
  • pour les boucles
  • while boucles
  • imprimer des relevés

Et peut-être quelques autres choses que la plupart des langues devraient avoir. Ensuite, utilisez un système de points. Attribuez au plus 1 point pour chaque élément si l'expression régulière est trouvée. De toute évidence, certaines langues utiliseront exactement la même syntaxe (les boucles for sont souvent écrites comme for(int i=0; i<x; ++i)si plusieurs langues pourraient chacune marquer un point pour la même chose, mais au moins vous réduisez la probabilité qu'il s'agisse d'une langue entièrement différente). Certains d'entre eux peuvent obtenir des scores de 0 dans tous les domaines (l'extrait de code ne contient pas du tout de fonction, par exemple), mais c'est parfaitement bien.

Combinez cela avec la solution de Jules, et cela devrait bien fonctionner. Peut-être aussi rechercher des fréquences de mots-clés pour un point supplémentaire.

mpen
la source
0

Intéressant. J'ai une tâche similaire pour reconnaître du texte dans différents formats. Propriétés YAML, JSON, XML ou Java? Même avec des erreurs de syntaxe, par exemple, je devrais distinguer JSON de XML avec confiance.

Je pense que la façon dont nous modélisons le problème est essentielle. Comme Mark l'a dit, la tokenisation d'un seul mot est nécessaire mais probablement pas suffisante. Nous aurons besoin de bigrammes, voire de trigrammes. Mais je pense qu'on peut aller plus loin à partir de là en sachant que l'on s'intéresse aux langages de programmation. Je remarque que presque tous les langages de programmation ont deux types uniques de jetons - symboles et mots - clés . Les symboles sont relativement faciles (certains symboles peuvent être des littéraux ne faisant pas partie du langage) à reconnaître. Ensuite, les bigrammes ou trigrammes de symboles prendront des structures de syntaxe uniques autour des symboles. Les mots clés sont une autre cible facile si l'ensemble de formation est suffisamment vaste et diversifié. Une fonctionnalité utile pourrait être des bigrammes autour de mots clés possibles. Un autre type de jeton intéressant est l' espace blanc. En fait, si nous tokenisons de la manière habituelle par un espace blanc, nous perdrons cette information. Je dirais que pour analyser les langages de programmation, nous conservons les jetons d'espacement car cela peut contenir des informations utiles sur la structure de la syntaxe.

Enfin, si je choisis un classificateur comme la forêt aléatoire, je vais explorer github et rassembler tout le code source public. La plupart des fichiers de code source peuvent être étiquetés par suffixe de fichier. Pour chaque fichier, je le diviserai au hasard en lignes vides en extraits de différentes tailles. Je vais ensuite extraire les fonctionnalités et entraîner le classificateur en utilisant les extraits étiquetés. Une fois la formation terminée, le classificateur peut être testé pour la précision et le rappel.

neurite
la source
0

La meilleure solution que j'ai rencontrée est d'utiliser le joyau du linguiste dans une application Ruby on Rails. C'est en quelque sorte une manière spécifique de le faire, mais cela fonctionne. Cela a été mentionné ci-dessus par @nisc mais je vais vous dire mes étapes exactes pour l'utiliser. (Certaines des commandes de ligne de commande suivantes sont spécifiques à ubuntu mais devraient être facilement traduites vers d'autres systèmes d'exploitation)

Si vous avez une application de rails qui ne vous dérange pas de jouer temporairement, créez un nouveau fichier dedans pour insérer votre extrait de code en question. (Si vous ne disposez pas des rails installés il y a un bon guide ici bien pour ubuntu Je recommande ce . Ensuite , exécutez rails new <name-your-app-dir>- vous dans ce répertoire. Tout ce que vous devez exécuter une application des rails est déjà là).

Une fois que vous avez une application de rails avec laquelle l'utiliser, ajoutez-la gem 'github-linguist'à votre Gemfile (littéralement juste appelée Gemfiledans le répertoire de votre application, pas d'ext).

Ensuite, installez ruby-dev ( sudo apt-get install ruby-dev)

Puis installez cmake ( sudo apt-get install cmake)

Maintenant, vous pouvez exécuter gem install github-linguist(si vous obtenez une erreur indiquant que icu est requis, faites sudo apt-get install libicu-devet réessayez)

(Vous devrez peut-être faire un sudo apt-get updateou sudo apt-get install makeou sudo apt-get install build-essentialsi ce qui précède n'a pas fonctionné)

Maintenant, tout est mis en place. Vous pouvez désormais l'utiliser à tout moment pour vérifier des extraits de code. Dans un éditeur de texte, ouvrez le fichier que vous avez créé pour insérer votre extrait de code (disons simplement que c'est, app/test.tplmais si vous connaissez l'extension de votre extrait, utilisez-la à la place de .tpl. Si vous ne connaissez pas l'extension, n'en utilisez pas une ). Collez maintenant votre extrait de code dans ce fichier. Accédez à la ligne de commande et exécutez bundle install(doit être dans le répertoire de votre application). Puis exécutez linguist app/test.tpl(plus généralement linguist <path-to-code-snippet-file>). Il vous indiquera le type, le type mime et la langue. Pour plusieurs fichiers (ou pour une utilisation générale avec une application ruby ​​/ rails), vous pouvez exécuter bundle exec linguist --breakdowndans le répertoire de votre application.

Cela semble demander beaucoup de travail supplémentaire, surtout si vous n'avez pas déjà de rails, mais vous n'avez en fait besoin de rien savoir sur les rails si vous suivez ces étapes et que je n'ai vraiment pas trouvé de meilleur moyen de détecter le langue d'un fichier / extrait de code.

StéphanieS
la source
0

Je crois qu'il n'y a pas de solution unique qui pourrait éventuellement identifier la langue d'un extrait de code, juste en fonction de cet extrait de code unique. Prenez le mot-clé print. Il peut apparaître dans n'importe quel nombre de langues, dont chacune est à des fins différentes, et avoir une syntaxe différente.

J'ai quelques conseils. J'écris actuellement un petit morceau de code pour mon site Web qui peut être utilisé pour identifier les langages de programmation. Comme la plupart des autres articles, il pourrait y avoir une vaste gamme de langages de programmation que vous n'avez tout simplement pas entendus, vous ne pouvez pas tous les expliquer.

Ce que j'ai fait, c'est que chaque langue peut être identifiée par une sélection de mots-clés. Par exemple, Python peut être identifié de plusieurs manières. C'est probablement plus facile si vous choisissez des «traits» qui sont certainement propres à la langue. Pour Python, je choisis le trait d'utiliser deux points pour démarrer un ensemble d'instructions, ce qui, je crois, est un trait assez unique (corrigez-moi si je me trompe).

Si, dans mon exemple, vous ne trouvez pas de deux-points pour démarrer un ensemble d'instructions, passez à un autre trait possible, disons en utilisant le defmot - clé pour définir une fonction. Maintenant, cela peut poser des problèmes, car Ruby utilise également le mot-clé defpour définir une fonction. La clé pour distinguer les deux (Python et Ruby) est d'utiliser différents niveaux de filtrage pour obtenir la meilleure correspondance. Ruby utilise le mot-clé endpour terminer une fonction, alors que Python n'a rien pour terminer une fonction, juste un retrait mais vous ne voulez pas y aller. Mais encore une fois, endpourrait aussi être Lua, encore un autre langage de programmation à ajouter au mélange.

Vous pouvez voir que les langages de programmation se superposent simplement trop. Un mot-clé qui pourrait être un mot-clé dans une langue pourrait se trouver être un mot-clé dans une autre langue. L'utilisation d'une combinaison de mots-clés qui vont souvent ensemble, comme ceux de Java, public static void main(String[] args)aide à éliminer ces problèmes.

Comme je l'ai déjà dit, votre meilleure chance est de rechercher des mots-clés relativement uniques ou des ensembles de mots-clés pour séparer l'un de l'autre. Et, si vous vous trompez, au moins vous avez essayé.

William Lee
la source
0

Configurez le brouilleur aléatoire comme

matrix S = matrix(GF(2),k,[random()<0.5for _ in range(k^2)]); while (rank(S) < k) : S[floor(k*random()),floor(k*random())] +=1;
Rakesh
la source
0

Ce site semble être assez bon pour identifier les langues, si vous voulez un moyen rapide de coller un extrait dans un formulaire Web, plutôt que de le faire par programme: http://dpaste.com/

drkvogel
la source