スニペットからプログラミング言語を検出する


114

コードスニペットで使用されているプログラミング言語を検出する最良の方法は何ですか?


1
事実上、無数の言語が存在します...それらのいずれかを検出しますか?それとも人気のある話だけですか?
スペンサールポート09年

人気のあるもの(C / C ++、C#、Java、Pascal、Python、VB.NET、PHP、JavaScript、そしておそらくHaskell)。
ジョアン・マトス

12
まあ、Haskellは聞いたことがないので人気がありません。;-)
ステファニーページ

22
Haskellを聞いたことがないのなら、プログラミング言語についてあまり知らないでしょう。
Akhorus

4
それをしないこのオンラインサービスがあります:algorithmia.com/algorithms/PetiteProgrammer/...
ベニー・ノイゲバウアー

回答:


99

スパムフィルターで使われている方法はとてもうまくいくと思います。スニペットを単語に分割します。次に、これらの単語の出現を既知のスニペットと比較し、興味のあるすべての言語について、このスニペットが言語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倍、defRuby で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)

1
フォーラムのソフトウェアでも使用する必要があります。ベイジアンフィルタリングに関するヒントをありがとう。
ジョアン・マトス

12
私はNLPクラスでこのようなことをしましたが、さらに一歩進めました。あなたは単一の単語の頻度ではなく、単語のペアとトリプルを見るのが好きではありません。たとえば、「public」は多くの言語のキーワードですが、「public static void」はC#でより一般的です。トリプル缶が見つからない場合は、バック2にフォール、その後、1
MPEN

1
単語をどこで分割するかについても考えたい場合があります。PHPでは、変数はで始まります。そのため、は変数に固執する必要があるため、単語の境界で分割$するべきではありません$。演算子は好き=>:=、単一のトークンとして一緒にスタックする必要がありますが、OTH は常に独立しているため、おそらくsで分割する必要があります{
mpen 2010年

2
うん。分割をまったく回避する方法は、ngramを使用することです。n個の長さの部分文字列をすべて取得します。たとえば、「puts foo」の5グラムは「puts」、「uts f」、「ts fo」、「s foo」です。この戦略は奇妙に思えるかもしれませんが、あなたが考えるよりもうまく機能します。人間が問題を解決する方法ではありません。どの方法が適切に機能するかを判断するには、両方をテストする必要があります...
Jules

2
ただし、一部の言語では構文がほとんどありません。また、一般的な変数名が言語のキーワードよりも支配的であると推測しています。基本的に、ハンガリー語で書かれたCコードがあり、変数名とハンガリー語のコメントがトレーニングデータに含まれている場合、ハンガリー語が含まれる他のソースはすべて「類似」していると判断されます。
tripleee 2011

26

他の人が解決した言語検出:

Ohlohのアプローチ:https : //github.com/blackducksw/ohcount/

Githubのアプローチ:https : //github.com/github/linguist


4
私はこれらのソリューションの両方を検討しましたが、どちらも要求された内容を正確に実行しません。彼らは主にファイル拡張子を調べて言語を判別するため、拡張子からの手掛かりがなければ、必ずしもスニペットを調べることはできません。
Hawkee

5
Githubのアプローチには、ベイジアン分類器も含まれています。それは主にファイル拡張子に基づいて言語候補を検出しますが、ファイル拡張子が複数の候補(たとえば、 "。h"-> C、C ++、ObjC)に一致する場合、入力コードサンプルをトークン化し、事前トレーニング済みセットに対して分類しますデータの。Githubバージョンは、拡張機能を見ることなく、常にコードをスキャンするように強制できます。
ベンジー2013年



5

それは非常に難しく、時には不可能です。この短いスニペットの言語は何ですか?

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

(ヒント:数ある中のどれでもかまいません。)

さまざまな言語を分析して、キーワードの頻度分析を使用して決定することができます。特定のキーワードのセットが特定の頻度でテキストに出現する場合、その言語はJavaなどである可能性があります。しかし、たとえばCの変数に同じ名前を付けることができるので、完全に間違いのないものは得られないと思いますJavaのキーワードとして、そして周波数分析はだまされます。

複雑さのレベルを上げると、構造を探すことができます。特定のキーワードが常に次のキーワードの後に​​来る場合は、より多くの手がかりが得られます。しかし、設計と実装がはるかに難しくなります。


26
まあ、いくつかの言語が可能であれば、検出器はすべての可能な候補を提供できます。
Steven Haryanto 2013年

または、最初に一致したものを与えることもできます。実際の使用例が構文の強調表示のようなものである場合、実際には違いはありません。一致する言語のいずれかがコードを正しく強調表示することを意味します。
jonschlinkert

5

代替は、使用することですhighlight.jsを、これを実行する構文の強調表示が、言語を識別するためにハイライト・プロセスの成功率を使用しています。原則として、任意の構文ハイライタコードベースを同じ方法で使用できますが、highlight.jsの優れた点は、言語検出が機能と見なされ、テスト目的で使用されることです

更新:私はこれを試してみましたが、うまくいきませんでした。圧縮されたJavaScriptは完全に混乱させました。つまり、トークナイザーは空白を区別します。一般に、ハイライトヒットをカウントするだけでは、信頼性は高くありません。より強力なパーサー、またはおそらく一致しないセクション数が、より適切に機能する可能性があります。


highlight.jsに含まれている言語データは、強調表示に必要な値に制限されています。これは、言語検出(特に少量のコード)には非常に不十分であることが判明しています。
アダムケネディ

大丈夫だと思います。このフィドルjsfiddle.net/3tgjnz10
sebilasse

4

まず、言語の特定のキーワークを見つけようとします。

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

3
問題は、これらのキーワードが変数名または文字列として、どの言語でも表示される可能性があることです。それと、使用されるキーワードには多くの重複があります。キーワードを探すだけでは不十分です。
mpen 2010年

2

それはあなたが持っているスニペットのタイプに依存しますが、私はそれを一連のトークナイザーを通して実行し、どの言語のBNFが有効であるかを確認しました。


すべての言語をBNFで記述することさえできません。キーワードを再定義してマクロを作成することが許可されている場合は、さらに難しくなります。Alsåはスニペットについて話しているので、BNFに対して部分一致を行う必要がありますが、これは難しく、エラーが発生しやすくなります。

2

素敵なパズル。

すべての言語を検出することは不可能だと思います。ただし、キートークンでトリガーできます。(特定の予約語とよく使用される文字の組み合わせ)。

ベン似たような構文を持つ言語はたくさんあります。したがって、スニペットのサイズによって異なります。


1

Prettifyは、プログラミング言語を検出する大丈夫な作業を行うJavaScriptパッケージです。

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

これは主に構文強調表示機能ですが、スニペットから言語を検出する目的で検出部分を抽出する方法がおそらくあるでしょう。


1
さらに調べてみると、prettifyは実際には言語を検出しないようですが、各要素の構文に従って強調表示しています。
Hawkee


1

これが必要だったので、自分で作成しました。 https://github.com/bertyhell/CodeClassifier

適切なフォルダにトレーニングファイルを追加することで、非常に簡単に拡張できます。C#で書かれました。しかし、コードが他の言語に簡単に変換されることを想像します。


0

これを実現する簡単な方法はないと思います。私はおそらく、特定の言語/言語クラスに固有の記号/共通キーワードのリストを生成します(たとえば、Cスタイル言語の波括弧、BASIC言語のDimおよびSubキーワード、Pythonのdefキーワード、関数型言語のletキーワード) 。その後、基本的な構文機能を使用してさらに絞り込むことができる場合があります。


0

言語間の最大の違いはその構造だと思います。したがって、私の考えは、すべての言語に共通する特定の要素を調べ、それらがどのように異なるかを確認することです。たとえば、正規表現を使用して次のようなものを選択できます。

  • 関数定義
  • 変数宣言
  • クラス宣言
  • コメント
  • forループ
  • whileループ
  • ステートメントの印刷

そしておそらく、ほとんどの言語が持つべきいくつかの他のこと。次に、ポイントシステムを使用します。正規表現が見つかった場合、各要素に対して最大1ポイントを獲得します。明らかに、一部の言語ではまったく同じ構文を使用します(forループは多くの場合、同じfor(int i=0; i<x; ++i)ように複数の言語がそれぞれポイントを獲得できるように記述されますが、少なくとも完全に異なる言語である可能性は低くなります)。それらのいくつかは、全面的に0をスコアリングする可能性があります(たとえば、スニペットには関数がまったく含まれていません)が、それは完全に問題ありません。

これをジュールのソリューションと組み合わせると、かなりうまくいくはずです。たぶん、余分なポイントのキーワードの頻度を探します。


0

面白い。さまざまな形式のテキストを認識する同様のタスクがあります。YAML、JSON、XML、またはJavaプロパティ?たとえば、構文エラーがあったとしても、JSONとXMLを区別して区別する必要があります。

問題をモデル化する方法が重要だと思います。マークが言ったように、単一の単語のトークン化は必要ですが、おそらく十分ではありません。バイグラムまたはトリグラムさえ必要になります。しかし、プログラミング言語を検討していることを知っていれば、そこから先に進むことができると思います。ほとんどすべてのプログラミング言語には、記号キーワードの 2種類のトークンがあります。記号は比較的簡単に認識できます(一部の記号は、言語の一部ではなくリテラルである場合があります)。次に、シンボルのバイグラムまたはトライグラムは、シンボルの周りの一意の構文構造を取得します。トレーニングセットが大きく、十分に多様である場合、キーワードは別の簡単なターゲットです。便利な機能は、可能なキーワードの周りのバイグラムです。別の興味深いタイプのトークンは空白です。実際、空白で通常の方法でトークン化すると、この情報は失われます。プログラミング言語を分析する場合、構文トークンに関する有用な情報が含まれている可能性があるため、空白トークンを保持します。

最後に、ランダムフォレストのような分類子を選択すると、githubをクロールしてすべてのパブリックソースコードを収集します。ほとんどのソースコードファイルは、ファイルサフィックスでラベル付けできます。ファイルごとに、空の行でランダムに分割して、さまざまなサイズのスニペットにします。次に、特徴を抽出し、ラベル付きスニペットを使用して分類子をトレーニングします。トレーニングが完了したら、分類子の精度と再現率をテストできます。


0

私が遭遇した最良の解決策は、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、アプリケーションのディレクトリで実行できます。

特にレールがまだない場合は特に多くの追加作業のようですが、これらの手順を実行すれば、実際にレールについて何も知る必要はありません。ファイル/コードスニペットの言語。


0

単一のスニペットに基づいて、スニペットの言語を特定できる単一のソリューションはないと思います。キーワードを取りprintます。さまざまな目的で使用され、さまざまな構文を持つ任意の数の言語で表示できます。

アドバイスがあります。私は現在、プログラミング言語を識別するために使用できる私のウェブサイト用の小さなコードを書いています。他のほとんどの投稿と同様に、単に聞いたことのない膨大な範囲のプログラミング言語があり、それらすべてを説明することはできません。

私がしたことは、各言語は選択したキーワードによって識別できるということです。たとえば、Pythonはさまざまな方法で識別できます。確かにその言語に固有の「特性」を選択する方がおそらく簡単です。Pythonの場合、コロンを使用して一連のステートメントを開始するという特性を選択します。これはかなりユニークな特性だと思います(私が間違っている場合は修正してください)。

私の例で、ステートメントセットを開始するためのコロンが見つからない場合、別の可能な特性に移動しdefます。たとえば、キーワードを使用して関数を定義するとします。Rubyでもキーワードdefを使用して関数を定義しているため、これにより問題が発生する可能性があります。2つ(PythonとRuby)を区別するための鍵は、さまざまなレベルのフィルタリングを使用して最適な一致を取得することです。Rubyはキーワードendを使用して関数を終了しますが、Pythonは関数を終了するために必要なものはなく、インデントを解除しますが、そこに行きたくありません。しかし、再び、endLua、ミックスに追加するさらに別のプログラミング言語である可能性もあります。

プログラミング言語は単純にオーバーレイしすぎていることがわかります。ある言語のキーワードである可能性がある1つのキーワードが、別の言語のキーワードである可能性があります。Javaのように、しばしば一緒になるキーワードの組み合わせを使用すると、public static void main(String[] args)これらの問題を排除するのに役立ちます。

すでに述べたように、あなたの最良の機会は、比較的ユニークなキーワードまたはキーワードのセットを探して、それらを互いに分離することです。そして、あなたがそれを間違えれば、少なくともあなたは成功しました。


0

のようなランダムスクランブラを設定します

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

プログラムで実行するのではなく、スニペットをWebフォームにすばやく貼り付ける方法が必要な場合、このサイトは言語の識別にかなり優れているようです。http//dpaste.com/

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.