コードスニペットで使用されているプログラミング言語を検出する最良の方法は何ですか?
コードスニペットで使用されているプログラミング言語を検出する最良の方法は何ですか?
回答:
スパムフィルターで使われている方法はとてもうまくいくと思います。スニペットを単語に分割します。次に、これらの単語の出現を既知のスニペットと比較し、興味のあるすべての言語について、このスニペットが言語Xで記述されている確率を計算します。
http://en.wikipedia.org/wiki/Bayesian_spam_filtering
基本的なメカニズムがあれば、新しい言語を追加するのは非常に簡単です。新しい言語でいくつかのスニペットを使用して検出器をトレーニングするだけです(オープンソースプロジェクトにフィードすることができます)。このようにして、「システム」はC#スニペットに表示され、「プット」はRubyスニペットに表示される可能性が高いことがわかります。
私は実際にこの方法を使用して、フォーラムソフトウェアのコードスニペットに言語検出を追加しました。あいまいな場合を除いて、100%動作しました。
print "Hello"
コードを見つけましょう。
コードが見つからなかったので、新しいコードを作成しました。少し単純ですが、私のテストでは機能します。現在、Rubyコードよりもはるかに多くのPythonコードをフィードすると、このコードは次のようになります。
def foo
puts "hi"
end
Pythonコードです(ただし、実際にはRubyです)。これは、Pythonにもdef
キーワードがあるためです。したがってdef
、Pythonで1000倍、def
Ruby で100 倍になった場合でも、Pythonと表示されることがputs
あります。end
Ruby固有である。これを修正するには、言語ごとに見られる単語を追跡し、どこかでそれを除算します(または各言語で同じ量のコードをフィードすることによって)。
それがあなたに役立つことを願っています:
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)
$
するべきではありません$
。演算子は好き=>
で:=
、単一のトークンとして一緒にスタックする必要がありますが、OTH は常に独立しているため、おそらくsで分割する必要があります{
。
他の人が解決した言語検出:
Ohlohのアプローチ:https : //github.com/blackducksw/ohcount/
Githubのアプローチ:https : //github.com/github/linguist
http://alexgorbatchev.com/wiki/SyntaxHighlighterで役立つ資料が見つかります。Alexは多くの時間を費やして、多数の異なる言語を解析する方法と、主要な構文要素を理解しました。
Guesslangは可能な解決策です:
http://guesslang.readthedocs.io/en/latest/index.html
SourceClassifierもあります。
https://github.com/chrislo/sourceclassifier/tree/master
ブログ記事で特定できないコードを見つけたので、この問題に興味を持ちました。この質問は「プログラミング言語を特定する」の最初の検索ヒットだったため、この回答を追加しました。
それは非常に難しく、時には不可能です。この短いスニペットの言語は何ですか?
int i = 5;
int k = 0;
for (int j = 100 ; j > i ; i++) {
j = j + 1000 / i;
k = k + i * j;
}
(ヒント:数ある中のどれでもかまいません。)
さまざまな言語を分析して、キーワードの頻度分析を使用して決定することができます。特定のキーワードのセットが特定の頻度でテキストに出現する場合、その言語はJavaなどである可能性があります。しかし、たとえばCの変数に同じ名前を付けることができるので、完全に間違いのないものは得られないと思いますJavaのキーワードとして、そして周波数分析はだまされます。
複雑さのレベルを上げると、構造を探すことができます。特定のキーワードが常に次のキーワードの後に来る場合は、より多くの手がかりが得られます。しかし、設計と実装がはるかに難しくなります。
代替は、使用することですhighlight.jsを、これを実行する構文の強調表示が、言語を識別するためにハイライト・プロセスの成功率を使用しています。原則として、任意の構文ハイライタコードベースを同じ方法で使用できますが、highlight.jsの優れた点は、言語検出が機能と見なされ、テスト目的で使用されることです。
更新:私はこれを試してみましたが、うまくいきませんでした。圧縮されたJavaScriptは完全に混乱させました。つまり、トークナイザーは空白を区別します。一般に、ハイライトヒットをカウントするだけでは、信頼性は高くありません。より強力なパーサー、またはおそらく一致しないセクション数が、より適切に機能する可能性があります。
まず、言語の特定のキーワークを見つけようとします。
"package, class, implements "=> JAVA
"<?php " => PHP
"include main fopen strcmp stdout "=>C
"cout"=> C++
etc...
それはあなたが持っているスニペットのタイプに依存しますが、私はそれを一連のトークナイザーを通して実行し、どの言語のBNFが有効であるかを確認しました。
Prettifyは、プログラミング言語を検出する大丈夫な作業を行うJavaScriptパッケージです。
http://code.google.com/p/google-code-prettify/
これは主に構文強調表示機能ですが、スニペットから言語を検出する目的で検出部分を抽出する方法がおそらくあるでしょう。
これが必要だったので、自分で作成しました。 https://github.com/bertyhell/CodeClassifier
適切なフォルダにトレーニングファイルを追加することで、非常に簡単に拡張できます。C#で書かれました。しかし、コードが他の言語に簡単に変換されることを想像します。
言語間の最大の違いはその構造だと思います。したがって、私の考えは、すべての言語に共通する特定の要素を調べ、それらがどのように異なるかを確認することです。たとえば、正規表現を使用して次のようなものを選択できます。
そしておそらく、ほとんどの言語が持つべきいくつかの他のこと。次に、ポイントシステムを使用します。正規表現が見つかった場合、各要素に対して最大1ポイントを獲得します。明らかに、一部の言語ではまったく同じ構文を使用します(forループは多くの場合、同じfor(int i=0; i<x; ++i)
ように複数の言語がそれぞれポイントを獲得できるように記述されますが、少なくとも完全に異なる言語である可能性は低くなります)。それらのいくつかは、全面的に0をスコアリングする可能性があります(たとえば、スニペットには関数がまったく含まれていません)が、それは完全に問題ありません。
これをジュールのソリューションと組み合わせると、かなりうまくいくはずです。たぶん、余分なポイントのキーワードの頻度を探します。
面白い。さまざまな形式のテキストを認識する同様のタスクがあります。YAML、JSON、XML、またはJavaプロパティ?たとえば、構文エラーがあったとしても、JSONとXMLを区別して区別する必要があります。
問題をモデル化する方法が重要だと思います。マークが言ったように、単一の単語のトークン化は必要ですが、おそらく十分ではありません。バイグラムまたはトリグラムさえ必要になります。しかし、プログラミング言語を検討していることを知っていれば、そこから先に進むことができると思います。ほとんどすべてのプログラミング言語には、記号とキーワードの 2種類のトークンがあります。記号は比較的簡単に認識できます(一部の記号は、言語の一部ではなくリテラルである場合があります)。次に、シンボルのバイグラムまたはトライグラムは、シンボルの周りの一意の構文構造を取得します。トレーニングセットが大きく、十分に多様である場合、キーワードは別の簡単なターゲットです。便利な機能は、可能なキーワードの周りのバイグラムです。別の興味深いタイプのトークンは空白です。実際、空白で通常の方法でトークン化すると、この情報は失われます。プログラミング言語を分析する場合、構文トークンに関する有用な情報が含まれている可能性があるため、空白トークンを保持します。
最後に、ランダムフォレストのような分類子を選択すると、githubをクロールしてすべてのパブリックソースコードを収集します。ほとんどのソースコードファイルは、ファイルサフィックスでラベル付けできます。ファイルごとに、空の行でランダムに分割して、さまざまなサイズのスニペットにします。次に、特徴を抽出し、ラベル付きスニペットを使用して分類子をトレーニングします。トレーニングが完了したら、分類子の精度と再現率をテストできます。
私が遭遇した最良の解決策は、Ruby on Railsアプリで言語学の宝石を使用することです。これは特定の方法で行うことができますが、機能します。これについては、@ niscで前述しましたが、実際の使用手順を説明します。(以下のコマンドラインコマンドの一部はubuntuに固有ですが、他のOSに簡単に変換できます)
一時的にいじっても構わないRailsアプリがある場合は、その中に新しいファイルを作成して、問題のコードスニペットを挿入します。(railsがインストールされていない場合、ubuntuにはこれをお勧めしますが、ここに優れたガイドがあります。次に、実行してそのディレクトリにcdします。railsアプリを実行するために必要なものはすべてそこにあります)。rails new <name-your-app-dir>
これを使用するRailsアプリを作成gem 'github-linguist'
したら、Gemfile に追加します(文字通りGemfile
、アプリディレクトリで呼び出され、extではありません)。
次にruby-devをインストールします(sudo apt-get install ruby-dev
)
次にcmakeをインストールします(sudo apt-get install cmake
)
これで実行できますgem install github-linguist
(icuが必要であるというエラーが発生した場合は、やり直しsudo apt-get install libicu-dev
てください)。
(あなたは何をする必要があるかもしれませんsudo apt-get update
か、sudo apt-get install make
またはsudo apt-get install build-essential
上記が機能しなかった場合)
これですべてがセットアップされました。これで、コードスニペットを確認したいときにいつでも使用できます。テキストエディターで、コードスニペットを挿入するために作成したファイルを開きます(単にそうだと言いapp/test.tpl
ますが、スニペットの拡張子がわかっている場合は、の代わりにそれを使用してください.tpl
。拡張子がわからない場合は使用しないでください。 )。コードスニペットをこのファイルに貼り付けます。コマンドラインに移動して実行bundle install
します(アプリケーションのディレクトリにある必要があります)。次に実行しますlinguist app/test.tpl
(より一般的にはlinguist <path-to-code-snippet-file>
)。タイプ、mimeタイプ、言語が表示されます。複数のファイル(またはruby / railsアプリでの一般的な使用)の場合bundle exec linguist --breakdown
、アプリケーションのディレクトリで実行できます。
特にレールがまだない場合は特に多くの追加作業のようですが、これらの手順を実行すれば、実際にレールについて何も知る必要はありません。ファイル/コードスニペットの言語。
単一のスニペットに基づいて、スニペットの言語を特定できる単一のソリューションはないと思います。キーワードを取りprint
ます。さまざまな目的で使用され、さまざまな構文を持つ任意の数の言語で表示できます。
アドバイスがあります。私は現在、プログラミング言語を識別するために使用できる私のウェブサイト用の小さなコードを書いています。他のほとんどの投稿と同様に、単に聞いたことのない膨大な範囲のプログラミング言語があり、それらすべてを説明することはできません。
私がしたことは、各言語は選択したキーワードによって識別できるということです。たとえば、Pythonはさまざまな方法で識別できます。確かにその言語に固有の「特性」を選択する方がおそらく簡単です。Pythonの場合、コロンを使用して一連のステートメントを開始するという特性を選択します。これはかなりユニークな特性だと思います(私が間違っている場合は修正してください)。
私の例で、ステートメントセットを開始するためのコロンが見つからない場合、別の可能な特性に移動しdef
ます。たとえば、キーワードを使用して関数を定義するとします。Rubyでもキーワードdef
を使用して関数を定義しているため、これにより問題が発生する可能性があります。2つ(PythonとRuby)を区別するための鍵は、さまざまなレベルのフィルタリングを使用して最適な一致を取得することです。Rubyはキーワードend
を使用して関数を終了しますが、Pythonは関数を終了するために必要なものはなく、インデントを解除しますが、そこに行きたくありません。しかし、再び、end
Lua、ミックスに追加するさらに別のプログラミング言語である可能性もあります。
プログラミング言語は単純にオーバーレイしすぎていることがわかります。ある言語のキーワードである可能性がある1つのキーワードが、別の言語のキーワードである可能性があります。Javaのように、しばしば一緒になるキーワードの組み合わせを使用すると、public static void main(String[] args)
これらの問題を排除するのに役立ちます。
すでに述べたように、あなたの最良の機会は、比較的ユニークなキーワードまたはキーワードのセットを探して、それらを互いに分離することです。そして、あなたがそれを間違えれば、少なくともあなたは成功しました。
プログラムで実行するのではなく、スニペットをWebフォームにすばやく貼り付ける方法が必要な場合、このサイトは言語の識別にかなり優れているようです。http://dpaste.com/