it-swarm.com.de

Programmiersprache aus einem Snippet erkennen

Was wäre der beste Weg, um herauszufinden, welche Programmiersprache in einem Code-Snippet verwendet wird?

104
João Matos

Ich denke, dass die in Spam-Filtern verwendete Methode sehr gut funktionieren würde. Sie teilen das Snippet in Wörter auf. Dann vergleichen Sie die Vorkommen dieser Wörter mit bekannten Ausschnitten und berechnen die Wahrscheinlichkeit, dass dieser Ausschnitt in der Sprache X für jede Sprache geschrieben wird, die Sie interessieren.

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

Wenn Sie über den grundlegenden Mechanismus verfügen, ist es sehr einfach, neue Sprachen hinzuzufügen: Trainieren Sie den Detektor einfach mit ein paar Ausschnitten in der neuen Sprache (Sie könnten ihm ein Open-Source-Projekt zuführen). Auf diese Weise lernt es, dass "System" wahrscheinlich in C # -Schnipsel erscheint und in Ruby-Snippets "platziert" wird.

Ich habe diese Methode tatsächlich verwendet, um die Codeausschnitte für Forensoftware mit Spracherkennung zu versehen. Es funktionierte zu 100%, außer in mehrdeutigen Fällen:

print "Hello"

Lass mich den Code finden.

Ich konnte den Code nicht finden und habe einen neuen Code erstellt. Es ist etwas simpel, aber es funktioniert für meine Tests. Wenn Sie derzeit viel mehr Python-Code als Ruby-Code eingeben, wird dieser Code wahrscheinlich sagen:

def foo
   puts "hi"
end

ist Python-Code (obwohl es wirklich Ruby ist). Dies liegt daran, dass Python auch ein def-Schlüsselwort hat. Wenn es also 1000x def in Python und 100x def in Ruby gesehen hat, kann es immer noch Python sagen, obwohl puts und end Ruby-spezifisch ist. Sie können dies beheben, indem Sie die Wörter, die pro Sprache angezeigt werden, nachverfolgen und irgendwo durch diese teilen (oder indem Sie in jeder Sprache die gleiche Menge Code eingeben).

Ich hoffe es hilft dir:

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)
96
Jules

Spracherkennung durch andere gelöst:

Ohlohs Ansatz: https://github.com/blackducksw/ohcount/

Githubs Ansatz: https://github.com/github/linguist

24
nisc

Hier finden Sie nützliches Material: http://alexgorbatchev.com/wiki/SyntaxHighlighter . Alex hat viel Zeit darauf verwendet, eine große Anzahl verschiedener Sprachen zu analysieren und was der Schlüssel ist Syntaxelemente sind.

7
Steve

Eine Alternative ist die Verwendung von highlight.js , das die Syntaxhervorhebung durchführt, jedoch die Erfolgsrate des Hervorhebungsprozesses zur Identifizierung der Sprache verwendet. Im Prinzip kann jede Syntax-Highlighter-Codebase auf dieselbe Weise verwendet werden, aber die schöne Sache bei highlight.js ist, dass die Spracherkennung als Feature betrachtet wird und für Testzwecke ist.

UPDATE: Ich habe es versucht und es hat nicht so gut funktioniert. Komprimiertes JavaScript verwechselt es vollständig, d. H. Der Tokenizer ist Whitespace-sensitiv. Im Allgemeinen scheint das Zählen von Höhepunkttreffern nicht sehr zuverlässig zu sein. Ein stärkerer Parser oder vielleicht nicht übereinstimmende Anzahl von Abschnitten funktioniert möglicherweise besser.

5
Andy Jackson

Es ist sehr schwer und manchmal unmöglich. Aus welcher Sprache stammt dieser kurze Ausschnitt?

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

(Hinweis: Es kann einer von mehreren sein.)

Sie können versuchen, verschiedene Sprachen zu analysieren und anhand der Häufigkeitsanalyse von Schlüsselwörtern zu entscheiden. Wenn bestimmte Sätze von Schlüsselwörtern mit bestimmten Häufigkeiten in einem Text vorkommen, ist die Sprache wahrscheinlich Java usw. Aber ich glaube nicht, dass Sie alles erhalten, was absolut idiotensicher ist, da Sie beispielsweise eine Variable in C denselben Namen nennen könnten als Schlüsselwort in Java, und die Häufigkeitsanalyse wird getäuscht.

Wenn Sie die Komplexität etwas verbessern, können Sie nach Strukturen suchen. Wenn ein bestimmtes Schlüsselwort immer nach einem anderen kommt, erhalten Sie weitere Hinweise. Es wird aber auch viel schwieriger zu entwerfen und umzusetzen.

5
user14070

Guesslang ist eine mögliche Lösung:

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

Es gibt auch SourceClassifier:

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

Ich interessierte mich für dieses Problem, nachdem ich in einem Blogartikel Code gefunden hatte, den ich nicht identifizieren konnte. Das Hinzufügen dieser Antwort seit dieser Frage war der erste Suchtreffer für "Programmiersprache identifizieren".

5
ElectricWarr

Zuerst würde ich versuchen, die spezifischen Schlüsselwerke einer Sprache zu finden, z.

"package, class, implements "=> Java
"<?php " => PHP
"include main fopen strcmp stdout "=>C
"cout"=> C++
etc...
3
Pierre

Es würde davon abhängen, welche Art von Snippet Sie haben, aber ich würde es durch eine Reihe von Tokenizer laufen lassen und sehen, für welche BNF-Sprache es sich als gültig erwiesen hat.

2

Ich brauchte das, also habe ich meine eigene erstellt . https://github.com/bertyhell/CodeClassifier

Es ist sehr einfach erweiterbar, indem eine Trainingsdatei im richtigen Ordner hinzugefügt wird .. _. Geschrieben in c #. Aber ich kann mir vorstellen, dass der Code leicht in jede andere Sprache konvertiert werden kann.

1
Berty

Schönes Puzzle.

Ich denke, es ist unmöglich, alle Sprachen zu erkennen. Sie könnten jedoch auf Schlüsselmarkern auslösen. (bestimmte reservierte Wörter und häufig verwendete Zeichenkombinationen).

Ben gibt es viele Sprachen mit ähnlicher Syntax. Es hängt also von der Größe des Snippets ab.

1
Toon Krijthe

Prettify ist ein Javascript-Paket, das Programmiersprachen gut erkennt:

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

Es ist hauptsächlich ein Syntax-Highlighter, aber es gibt wahrscheinlich eine Möglichkeit, den Erkennungsteil zu extrahieren, um die Sprache aus einem Snippet zu ermitteln.

1
Hawkee

Richten Sie den zufälligen Scrambler gerne ein

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;
0
Rakesh

Ich denke, der größte Unterschied zwischen den Sprachen ist die Struktur. Meine Idee wäre also, bestimmte gemeinsame Elemente in allen Sprachen zu betrachten und zu sehen, wie sie sich unterscheiden. Sie können beispielsweise Regex verwenden, um folgende Dinge hervorzuheben:

  • funktionsdefinitionen
  • variablendeklarationen
  • klassenerklärungen
  • bemerkungen
  • für Schleifen
  • während Schleifen
  • anweisungen ausdrucken

Und vielleicht ein paar andere Dinge, die die meisten Sprachen haben sollten. Dann verwenden Sie ein Punktesystem. Vergeben Sie höchstens 1 Punkt für jedes Element, wenn der Regex gefunden wird. Offensichtlich verwenden einige Sprachen die gleiche Syntax (Schleifen werden oft wie for(int i=0; i<x; ++i) geschrieben), so dass mehrere Sprachen jeweils einen Punkt für dasselbe Ergebnis erzielen können, aber zumindest verringern Sie die Wahrscheinlichkeit, dass es sich um eine völlig andere Sprache handelt. Einige von ihnen können auf der ganzen Linie 0 Punkte erzielen (das Snippet enthält beispielsweise überhaupt keine Funktion), aber das ist vollkommen in Ordnung.

Kombinieren Sie dies mit der Lösung von Jules, und es sollte ziemlich gut funktionieren. Suchen Sie möglicherweise auch nach Häufigkeiten von Schlüsselwörtern für einen zusätzlichen Punkt.

0
mpen

Die beste Lösung, die ich gefunden habe, ist die Verwendung des Linguist-Gem in einer Ruby on Rails-App. Es ist eine bestimmte Art, es zu tun, aber es funktioniert. Dies wurde oben von @nisc erwähnt, aber ich werde Ihnen meine genauen Schritte für die Verwendung erklären. (Einige der folgenden Befehlszeilenbefehle sind spezifisch für Ubuntu, sollten jedoch leicht in andere Betriebssysteme übersetzt werden.)

Wenn Sie eine Rails-App haben, mit der Sie vorübergehend nichts anfangen möchten, erstellen Sie eine neue Datei, um das betreffende Code-Snippet einzufügen. (Wenn Sie Rails nicht installiert haben, gibt es eine gute Anleitung hier obwohl ich für Ubuntu dieses empfehle. Dann führen Sie Rails new <name-your-app-dir> und cd in dieses Verzeichnis. Alles, was Sie zum Ausführen einer Rails-App benötigen, ist bereits vorhanden.) .

Wenn Sie eine Rails-App zur Verwendung mit haben, fügen Sie gem 'github-linguist' zu Ihrem Gemfile hinzu (wörtlich nur Gemfile in Ihrem App-Verzeichnis, kein Ext.). 

Dann installiere Ruby-dev (Sudo apt-get install Ruby-dev

Dann installieren Sie cmake (Sudo apt-get install cmake)

Jetzt können Sie gem install github-linguist ausführen (wenn Sie eine Fehlermeldung erhalten, dass icu erforderlich ist, tun Sie Sudo apt-get install libicu-dev und versuchen Sie es erneut)

(Möglicherweise müssen Sie einen Sudo apt-get update oder Sudo apt-get install make oder Sudo apt-get install build-essential ausführen, wenn dies nicht funktioniert hat.

Jetzt ist alles eingerichtet. Sie können dies jetzt verwenden, wenn Sie Code-Snippets überprüfen möchten. Öffnen Sie in einem Texteditor die Datei, die Sie erstellt haben, um Ihr Code-Snippet einzufügen (sagen wir nur, es ist app/test.tpl, aber wenn Sie die Erweiterung Ihres Snippets kennen, verwenden Sie diese anstelle von .tpl. Wenn Sie die Erweiterung nicht kennen, dann nicht verwende eins). Fügen Sie nun Ihr Code-Snippet in diese Datei ein. Gehen Sie zur Befehlszeile und führen Sie bundle install aus (muss sich im Verzeichnis Ihrer Anwendung befinden). Führen Sie dann linguist app/test.tpl aus (allgemeiner linguist <path-to-code-snippet-file>). Es wird Ihnen der Typ, der Mime-Typ und die Sprache angezeigt. Bei mehreren Dateien (oder zur allgemeinen Verwendung mit einer Ruby/Rails-App) können Sie bundle exec linguist --breakdown im Verzeichnis Ihrer Anwendung ausführen.

Es scheint eine Menge zusätzlicher Arbeit zu sein, vor allem, wenn Sie nicht bereits Rails haben, aber Sie müssen nicht wirklich ALLES über Rails wissen, wenn Sie diesen Schritten folgen und ich habe wirklich keinen besseren Weg gefunden, das zu erkennen Sprache eines Datei-/Code-Snippets.

0
StephanieS

Ich glaube, dass es keine einzige Lösung gibt, die möglicherweise erkennen kann, in welcher Sprache sich ein Snippet befindet, nur basierend auf diesem einzelnen Snippet. Nehmen Sie das Schlüsselwort print. Es kann in einer beliebigen Anzahl von Sprachen erscheinen, von denen jede zu unterschiedlichen Zwecken dient und unterschiedliche Syntax hat.

Ich habe ein paar Ratschläge. Ich schreibe gerade ein kleines Stück Code für meine Website, mit dem Programmiersprachen identifiziert werden können. Wie bei den meisten anderen Beiträgen könnte es eine Reihe von (riesigen Programmiersprachen geben, die Sie einfach nicht gehört haben.

Was ich getan habe ist, dass jede Sprache durch eine Auswahl von Schlüsselwörtern identifiziert werden kann. Zum Beispiel könnte Python auf verschiedene Arten identifiziert werden. Es ist wahrscheinlich einfacher, wenn Sie "Merkmale" auswählen, die sicherlich auch für die Sprache einzigartig sind. Für Python wähle ich das Merkmal der Verwendung von Doppelpunkten, um eine Reihe von Anweisungen zu starten, die meiner Meinung nach ein ziemlich einzigartiges Merkmal sind (korrigieren Sie mich, wenn ich falsch liege).

Wenn Sie in meinem Beispiel keinen Doppelpunkt zum Starten eines Anweisungssatzes finden können, wechseln Sie zu einem anderen möglichen Merkmal. Nehmen wir an, Sie verwenden das Schlüsselwort def, um eine Funktion zu definieren. Nun kann dies einige Probleme verursachen, da Ruby auch das Schlüsselwort def verwendet, um eine Funktion zu definieren. Der Schlüssel zum Unterscheiden der beiden (Python und Ruby) ist die Verwendung verschiedener Filterstufen, um die beste Übereinstimmung zu erzielen. Ruby verwendet das Schlüsselwort end, um eine Funktion zu beenden, wohingegen Python keine Funktion hat, um eine Funktion zu beenden, nur einen Rückzug, aber Sie möchten nicht dorthin gehen. Aber auch end könnte Lua sein, eine weitere Programmiersprache, die dem Mix hinzugefügt werden kann.

Man kann sehen, dass sich die Programmiersprachen einfach zu sehr überlagern. Ein Schlüsselwort, das ein Schlüsselwort in einer Sprache sein könnte, könnte ein Schlüsselwort in einer anderen Sprache sein. Die Verwendung einer Kombination von Keywords, die oft zusammen passen, wie Javas public static void main(String[] args), hilft dabei, diese Probleme zu beseitigen.

Wie ich bereits gesagt habe, besteht die beste Chance darin, relativ eindeutige Keywords oder Keyword-Sätze zu suchen, um sie voneinander zu trennen. Und wenn Sie es falsch verstehen, hatten Sie zumindest einen Versuch.

0
William Lee

Ich würde nicht glauben, dass es einen einfachen Weg geben würde, dies zu erreichen. Ich würde wahrscheinlich Listen von Symbolen/allgemeinen Schlüsselwörtern generieren, die für bestimmte Sprachen/Sprachklassen eindeutig sind (z. B. geschweifte Klammern für die Sprache C, die Schlüsselwörter Dim und Sub für BASIC-Sprachen, das Schlüsselwort def für Python, das Schlüsselwort let für funktionale Sprachen) . Sie können dann möglicherweise grundlegende Syntaxfunktionen verwenden, um sie noch weiter einzugrenzen.

0
Noldorin

Interessant. Ich habe eine ähnliche Aufgabe, um Text in verschiedenen Formaten zu erkennen. YAML-, JSON-, XML- oder Java-Eigenschaften? Selbst bei Syntaxfehlern sollte ich beispielsweise JSON von XML mit Zuversicht unterscheiden.

Ich schätze, wie wir das Problem modellieren, ist kritisch. Wie Mark sagte, ist die Single-Word-Tokenisierung notwendig, aber wahrscheinlich nicht ausreichend. Wir brauchen Bigramme oder sogar Trigramme. Aber ich denke, wir können noch weiter gehen und wissen, dass wir Programmiersprachen suchen. Ich stelle fest, dass fast jede Programmiersprache zwei eindeutige Typen von Token - Symbolen und Schlüsselwörtern hat. Symbole sind relativ leicht zu erkennen (einige Symbole können Literale sein, die nicht Teil der Sprache sind). Dann nehmen Bigramme oder Trigramme von Symbolen einzigartige Syntaxstrukturen um Symbole auf. Keywords sind ein weiteres einfaches Ziel, wenn das Trainingsangebot groß und vielfältig genug ist. Eine nützliche Funktion könnten Bigramme rund um mögliche Schlüsselwörter sein. Eine andere interessante Art von Token ist Whitespace . Wenn wir in der üblichen Weise durch Leerzeichen kennzeichnen, verlieren wir diese Informationen. Ich würde sagen, für die Analyse von Programmiersprachen behalten wir die Whitespace-Token bei, da diese nützliche Informationen über die Syntaxstruktur enthalten können.

Wenn ich schließlich einen Klassifizierer wie einen zufälligen Wald auswähle, werde ich Github crawlen und den gesamten öffentlichen Quellcode sammeln. Der größte Teil der Quellcodedatei kann mit einem Dateisuffix gekennzeichnet werden. Für jede Datei werde ich sie bei leeren Zeilen nach dem Zufallsprinzip in Snippets unterschiedlicher Größe aufteilen. Ich werde dann die Features extrahieren und den Klassifikator anhand der gekennzeichneten Ausschnitte trainieren. Nach dem Training kann der Klassifikator auf Genauigkeit und Rückruf getestet werden.

0
neurite