从代码片段中检测编程语言
什么是检测代码片段中使用哪种编程语言的最佳方法?
我认为在垃圾邮件filter中使用的方法将工作得很好。 你把这个片段分成几个字。 然后,将这些单词的出现次数与已知片段进行比较,然后计算出您感兴趣的每种语言的此片段用X语言编写的概率。
http://en.wikipedia.org/wiki/Bayesian_spam_filtering
如果你有基本的机制,那么添加新的语言是非常简单的:只需要用新的语言来训练探测器(你可以给它一个开源项目)。 这样就可以知道“系统”可能出现在C#代码片段中,而“放入”Ruby代码片段中。
我实际上已经使用这种方法来将语言检测添加到论坛软件的代码片段中。 它在100%的时间里工作,除了模棱两可的情况:
print "Hello"
让我find代码。
我找不到代码,所以我做了一个新的代码。 这有点简单,但它适用于我的testing。 目前,如果您比Ruby代码更多地使用Python代码,则可能会说这个代码:
def foo puts "hi" end
是Python代码(尽pipe它确实是Ruby)。 这是因为Python也有def
关键字。 因此,如果在Python中看到1000x def
和在Ruby中看到100x def
,那么即使puts
和end
是特定于Ruby的,它仍然可以说Python。 你可以通过跟踪每种语言所看到的单词并将其分割(或者通过在每种语言中提供相同数量的代码)来解决这个问题。
我希望它可以帮助你:
class Classifier def initialize @data = {} @totals = Hash.new(1) end def words(code) code.split(/[^az]/).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)
他人解决的语言检测:
Ohloh的方法: https : //github.com/blackducksw/ohcount/
Github的方法: https : //github.com/github/linguist
你可能会在这里find一些有用的材料: http : //alexgorbatchev.com/wiki/SyntaxHighlighter 。 亚历克斯花了很多时间研究如何parsing大量不同的语言,以及关键的语法元素是什么。
这是非常困难的,有时是不可能的。 这个短片段来自哪种语言?
int i = 5; int k = 0; for (int j = 100 ; j > i ; i++) { j = j + 1000 / i; k = k + i * j; }
(提示:可以是任何一个。)
您可以尝试分析各种语言,并尝试使用关键字的频率分析。 如果某些关键字集合在文本中出现某些频率,那么语言可能就是Java等等。但是我不认为你会得到任何完全可以certificate的东西,比如你可以用同名的variables名作为Java中的关键字,频率分析将被愚弄。
如果你把它放在一个复杂的地方,你可以寻找结构,如果某个关键字总是出现在另一个关键字之后,那么这个关键词就会有更多的线索。 但是devise和实施也会困难得多。
另一种方法是使用highlight.js ,它执行语法高亮显示,但使用突出显示过程的成功率来识别语言。 原则上,任何语法高亮度代码库都可以以相同的方式使用,但是highlight.js的好处在于语言检测被认为是一个特性, 用于testing目的 。
更新:我试了这个,它并没有很好的工作。 压缩的JavaScript完全混淆了它,即标记器是空白敏感的。 一般来说,只计算高亮命中似乎并不可靠。 更强大的parsing器,或者可能无法匹配的部分数量可能会更好。
首先,我会尝试find一种语言的具体关键词,例如
"package, class, implements "=> JAVA "<?php " => PHP "include main fopen strcmp stdout "=>C "cout"=> C++ etc...
这取决于你有什么types的代码片段,但是我会通过一系列代词器来运行它,并且看看哪种语言的BNF是有效的。
很好的拼图。
我认为检测所有语言是不可能的。 但是你可以触发关键的令牌。 (某些保留字和经常使用的字符组合)。
Ben有很多类似语法的语言。 所以这取决于片段的大小。
美化是一个Javascript包,做一个好的工作,检测编程语言:
http://code.google.com/p/google-code-prettify/
它主要是一个语法高亮显示,但可能有一种方法来提取检测部分,以便从一个片段中检测语言。
我需要这个,所以我创造了我自己的。 https://github.com/bertyhell/CodeClassifier
通过在正确的文件夹中添加培训文件,非常容易扩展。 用c#写的。 但我想代码很容易转换为任何其他语言。
我不认为会有一个简单的方法来完成这一点。 我可能会生成某些语言/类语言所特有的符号/常用关键字列表(例如,C风格语言的大括号,BASIC语言的Dim和Sub关键字,Python的def关键字,函数式语言的let关键字) 。 然后,您可以使用基本的语法function进一步缩小范围。
我认为语言之间最大的区别在于它的结构。 所以我的想法是查看所有语言的某些共同元素,看看它们有何不同。 例如,您可以使用正则expression式来挑选如下内容:
- 函数定义
- variables声明
- 类声明
- 注释
- for循环
- while循环
- 打印报表
也许还有大多数语言应该有的其他一些东西。 然后使用点系统。 如果find正则expression式,每个元素至多得1分。 很明显,一些语言会使用完全相同的语法(for循环通常被写for(int i=0; i<x; ++i)
所以多种语言都可以为同一个事物打分,重新降低它成为完全不同的语言的可能性)。 他们中的一些人可能会在整个棋盘上得分0(例如,该片段根本不包含任何function),但是这样做确实很好。
结合Jules的解决scheme,它应该工作得很好。 也许还可以查找关键字的频率以获得额外的点数。
有趣。 我有类似的任务来识别不同格式的文本。 YAML,JSON,XML或Java属性? 即使有语法错误,例如,我应该自信地将XML从JSON中分离出来。
我想我们如何模拟问题至关重要。 正如马克所说,单词分词是必要的,但可能还不够。 我们将需要bigrams,甚至trigrams。 但是我认为我们可以从那里进一步知道我们正在看编程语言。 我注意到几乎所有的编程语言都有两种独特的标记types – 符号和关键字 。 符号是相对容易的(一些符号可能不是文字的一部分),以识别。 然后,符号的三angular形或三angular形将在符号周围拾取唯一的语法结构。 如果训练集足够大而且多样,关键字是另一个容易的目标。 一个有用的function可能是围绕可能的关键字bigrams。 另一个有趣的令牌types是空白 。 实际上,如果我们用空白的方式按常规的方式进行标记,我们将会丢失这些信息。 我会说,为了分析编程语言,我们保留空白标记,因为这可能带有关于语法结构的有用信息。
最后,如果我select像随机森林这样的分类器,我将抓取github并收集所有的公共源代码。 大部分的源代码文件都可以用文件后缀来标记。 对于每个文件,我将随机地将它分成不同大小的片段。 然后,我将提取特征并使用标记的片段训练分类器。 训练完成后,分类器可以进行精确度和召回testing。
我碰到的最佳解决scheme是在Ruby on Rails应用程序中使用语言gem 。 这是一个特定的方式来做到这一点,但它的工作原理。 这是由@nisc上面提到的,但我会告诉你我使用它的确切步骤。 (下面的一些命令行命令是特定于Ubuntu的,但应该很容易转换到其他操作系统)
如果你有任何你不介意的Rails应用程序,请在其中创build一个新文件来插入有问题的代码片段。 (如果你没有安装rails,这里有一个很好的指导,虽然对于ubuntu,我推荐这个 ,然后运行rails new <name-your-app-dir>
然后cd进入该目录,运行rails应用程序所需的所有东西那里)。
在你有一个rails应用程序来使用它之后,把gem'github gem 'github-linguist'
到你的Gemfile(在你的应用程序目录中的字面名字就是Gemfile
,没有分机)。
然后安装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>
)。 它会告诉你的types,MIMEtypes和语言。 对于多个文件(或通常与ruby / rails应用程序一起使用),您可以在应用程序目录中运行bundle exec linguist --breakdown
。
这看起来像很多额外的工作,尤其是如果你还没有轨道,但你实际上不需要知道关于轨道的任何事情,如果你按照这些步骤,我真的没有find一个更好的方法来检测文件/代码片段的语言。
我相信没有单一的解决scheme可以识别片段的语言,只是基于这个单独的片段。 采取关键字print
。 它可以以任何数量的语言出现,每种语言都是出于不同目的,并且具有不同的语法。
我有一些build议。 我正在为我的网站编写一小段代码,可以用来识别编程语言。 像大多数其他职位一样,可能有大量的编程语言,你根本没有听说过,你不能说明全部。
我所做的是每种语言都可以通过select关键字来识别。 例如,Python可以通过多种方式来识别。 如果你select语言特有的“特质”,这可能会更容易一些。 对于Python,我select使用冒号来启动一组语句,我相信这是一个相当独特的特征(纠正我,如果我错了)。
如果,在我的例子中,你不能find一个冒号开始一个语句集,然后移动到另一个可能的特质,比如使用def
关键字定义一个函数。 现在这可能会导致一些问题,因为Ruby也使用关键字def
来定义一个函数。 告诉两者(Python和Ruby)不同的关键是使用不同级别的过滤来获得最佳匹配。 Ruby使用关键字end
来完成一个函数,而Python没有任何东西来完成一个函数,只是一个缩进,但你不想去那里。 但是, end
也可能是Lua,而另一种编程语言将会join混合。
你可以看到,编程语言只是覆盖太多。 一种语言中可能成为关键字的关键字可能恰好是另一种语言的关键词。 使用经常一起使用的关键字组合,例如Java的public static void main(String[] args)
有助于消除这些问题。
正如我已经说过的,你最好的机会是寻找相对独特的关键字或关键字集来区分一个。 而且,如果你弄错了,至less你得走了。
随机设置随机扰码器
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;