125 votes

Détecter le langage de programmation à partir d'un extrait de texte

Quel serait le meilleur moyen de détecter le langage de programmation utilisé dans un extrait de code ?

1 votes

Il existe pratiquement un nombre infini de langues... voulez-vous en détecter une seule ? Ou est-ce qu'on parle seulement des langues les plus populaires ?

0 votes

Seulement les plus populaires (C/C++, C#, Java, Pascal, Python, VB.NET. PHP, JavaScript et peut-être Haskell).

13 votes

Haskell ne doit pas être populaire puisque je n'en ai jamais entendu parler ;-)

101voto

Jules Points 3603

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

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

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

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

print "Hello"

Laissez-moi trouver le code.

Je n'ai pas pu trouver le code alors j'en ai fait un nouveau. Il est un peu simpliste mais il fonctionne pour mes tests. Actuellement, si vous lui donnez beaucoup plus de code Python que de code Ruby, il est susceptible de dire que ce code :

def foo
   puts "hi"
end

est du code Python (bien qu'il s'agisse en réalité de Ruby). Ceci est dû au fait que Python possède un def mot-clé aussi. Donc, s'il a vu 1000x def en Python et 100x def en Ruby, il se peut que l'on dise Python même si puts y end est spécifique à Ruby. Vous pourriez résoudre ce problème en comptabilisant le nombre de mots vus par langue et en le divisant par ce chiffre (ou en lui fournissant une quantité égale de code dans chaque langue).

J'espère que cela vous aidera :

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)

1 votes

J'ai également besoin de l'utiliser dans un logiciel de forum. Merci pour l'astuce concernant le filtrage bayésien.

12 votes

J'ai fait quelque chose comme ça dans mon cours de PNL, mais nous sommes allés un peu plus loin. Vous n'aimez pas regarder les fréquences d'une simple 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 est introuvable, on revient à 2, puis à 1.

1 votes

Vous pouvez aussi penser à la façon dont vous séparez les mots. En PHP, les variables commencent par $ alors peut-être que vous ne devrait pas être divisé sur les limites des mots, parce que le $ devrait s'en tenir à la variable. Des opérateurs comme => y := devraient être collés ensemble comme un seul jeton, mais d'autre part, vous avez probablement devrait se partager { parce qu'ils sont toujours autonomes.

26voto

nisc Points 1182

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

4 votes

J'ai examiné ces deux solutions et aucune ne permet de faire exactement ce qui a été demandé. Ils regardent principalement les extensions de fichiers pour déterminer la langue, donc ils ne peuvent pas nécessairement examiner un extrait sans l'indice de l'extension.

5 votes

L'approche de Github comprend désormais aussi un classificateur bayésien. Il détecte principalement un langage candidat sur la base de l'extension de fichier, mais lorsqu'une extension de fichier correspond à plusieurs candidats (par exemple, ".h" --> C, C++, ObjC), il segmente l'échantillon de code en entrée et le classe par rapport à un ensemble de données pré-entraînées. La version Github peut être forcée à scanner le code toujours sans regarder l'extension aussi.

9voto

ElectricWarr Points 243

Le 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 ne pouvais pas identifier. J'ajoute cette réponse car cette question a été le premier résultat de recherche pour "identifier le langage de programmation".

7voto

Steve Points 1386

Vous pourriez y trouver des informations utiles : http://alexgorbatchev.com/wiki/SyntaxHighlighter . Alex a passé beaucoup de temps à comprendre comment analyser un grand nombre de langues différentes et quels sont les éléments syntaxiques clés.

5voto

Andy Jackson Points 247

Une alternative est d'utiliser highlight.js qui effectue une coloration syntaxique mais utilise le taux de réussite du processus de coloration pour identifier la langue. En principe, n'importe quelle base de code de surligneur syntaxique pourrait être utilisée de la même manière, mais ce qui est bien avec highlight.js, c'est que la détection de la langue est considérée comme une fonction et est utilisé à des fins de test .

UPDATE : J'ai essayé et ça n'a pas très bien marché. Le JavaScript compressé l'a complètement confondu, c'est-à-dire que le tokenizer est sensible aux espaces blancs. De manière générale, le simple fait de compter les occurrences de mise en évidence ne semble pas très fiable. Un analyseur syntaxique plus puissant, ou peut-être un comptage des sections non appariées, pourrait mieux fonctionner.

0 votes

Les données relatives à la langue incluses dans highlight.js sont limitées aux valeurs nécessaires à la mise en évidence, ce qui s'avère tout à fait insuffisant pour la détection de la langue (surtout pour de petites quantités de code).

0 votes

Je pense que c'est bon, vérifiez avec ce fiddle jsfiddle.net/3tgjnz10

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X