在一段代码中检测使用哪种编程语言的最佳方法是什么?
答案 0 :(得分:97)
我认为垃圾邮件过滤器中使用的方法可以很好地运行。您将片段拆分为单词。然后,将这些单词的出现与已知片段进行比较,并计算出您感兴趣的每种语言都使用语言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
关键字。因此,如果在Ruby中看到1000x def
,在Ruby中看到100x def
,那么即使puts
和end
是特定于Ruby的,它仍然会说Python。您可以通过跟踪每种语言所看到的单词并将其除以某处(或通过在每种语言中提供相同数量的代码)来解决此问题。
我希望它可以帮到你:
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 :(得分:25)
其他人解决的语言检测:
Ohloh的方法:https://github.com/blackducksw/ohcount/
Github的方法:https://github.com/github/linguist
答案 2 :(得分:7)
您可以在此处找到一些有用的资料:http://alexgorbatchev.com/wiki/SyntaxHighlighter。 Alex花了很多时间来弄清楚如何解析大量不同的语言,以及关键的语法元素是什么。
答案 3 :(得分:5)
Guesslang是一种可能的解决方案:
http://guesslang.readthedocs.io/en/latest/index.html
还有SourceClassifier:
https://github.com/chrislo/sourceclassifier/tree/master
在博客文章中找到一些我无法识别的代码之后,我对这个问题产生了兴趣。添加此答案,因为这个问题是第一次搜索"识别编程语言"。
答案 4 :(得分: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中的关键字,频率分析将被愚弄。
如果你把它提高到一个复杂程度,你可以寻找结构,如果某个关键字总是在另一个关键字之后,那将为你提供更多线索。但是设计和实施起来也要困难得多。
答案 5 :(得分:5)
另一种方法是使用highlight.js,它执行语法突出显示,但使用突出显示过程的成功率来识别语言。原则上,任何语法高亮显示器代码库都可以以相同的方式使用,但是关于highlight.js的好处是语言检测被认为是一个特征并且是used for testing purposes。
更新:我试过这个并没有那么好用。压缩的JavaScript完全混淆了它,即标记化器对空白敏感。一般来说,只计算高亮点击似乎不太可靠。更强大的解析器,或者可能无法比拟的部分数量,可能会更好。
答案 6 :(得分:3)
首先,我会尝试找到某种语言的特定关键字,例如
"package, class, implements "=> JAVA
"<?php " => PHP
"include main fopen strcmp stdout "=>C
"cout"=> C++
etc...
答案 7 :(得分:2)
这取决于你拥有什么类型的代码片段,但我会通过一系列标记器来运行它,看看它出现的哪种语言的BNF是有效的。
答案 8 :(得分:1)
Prettify是一个Javascript包,可以很好地检测编程语言:
http://code.google.com/p/google-code-prettify/
它主要是一种语法荧光笔,但可能有一种方法可以提取检测部分,以便从一个片段中检测语言。
答案 9 :(得分:1)
我需要这个,所以我创造了自己的。 https://github.com/bertyhell/CodeClassifier
通过在正确的文件夹中添加培训文件,可以非常轻松地扩展。 用c#编写。但我想这段代码很容易转换成任何其他语言。
答案 10 :(得分:1)
很好的谜题。
我认为检测所有语言是不可能的。但是你可以触发关键令牌。 (某些保留字和经常使用的字符组合)。
Ben有很多语法相似的语言。所以它取决于代码段的大小。
答案 11 :(得分:0)
我认为语言之间最大的区别在于它的结构。所以我的想法是查看所有语言中的某些共同元素,看看它们有何不同。例如,您可以使用正则表达式来选择以下内容:
也许还有其他大多数语言应该具备的东西。然后使用点系统。如果找到正则表达式,则每个元素最多奖励1分。显然,有些语言会使用完全相同的语法(for循环通常写成for(int i=0; i<x; ++i)
,所以多种语言都可以为同一个东西得分,但至少你减少了它完全不同的可能性语言)。他们中的一些人可能会在整个棋盘上得分为0(例如,片段根本不包含任何功能),但这完全没问题。
将此与Jules的解决方案相结合,它应该可以很好地工作。也许还要寻找额外点的关键词频率。
答案 12 :(得分:0)
有趣。我有类似的任务来识别不同格式的文本。 YAML,JSON,XML或Java属性?例如,即使出现语法错误,我也应该放心地从XML中分辨出JSON。
我认为我们如何对问题进行建模至关重要。正如马克所说,单字标记化是必要的,但可能还不够。我们需要双胞胎,甚至三卦。但我认为我们可以从那里进一步了解我们正在研究编程语言。我注意到几乎所有编程语言都有两种独特类型的标记 - 符号和关键字。识别时,符号相对容易(某些符号可能是文字不是语言的一部分)。然后,符号的双字母或三字符将在符号周围拾取独特的语法结构。如果训练集足够大且多样化,关键词是另一个容易的目标。一个有用的功能可能是关于可能的关键字的bigrams。另一种有趣的令牌是空白。实际上,如果我们以通常的方式用空格标记,我们将丢失这些信息。我要说的是,为了分析编程语言,我们保留了空格标记,因为这可能带有关于语法结构的有用信息。
最后,如果我选择像随机森林这样的分类器,我将抓取github并收集所有公共源代码。大多数源代码文件都可以用文件后缀标记。对于每个文件,我会将它在空行中随机分成各种大小的片段。然后,我将使用标记的片段提取功能并训练分类器。训练完成后,可以测试分类器的精确度和召回率。
答案 13 :(得分:0)
我认为没有一种简单的方法可以实现这一目标。我可能会生成某些语言/类别语言所特有的符号/常用关键字列表(例如,C风格语言的大括号,BASIC语言的Dim和Sub关键字,Python的def关键字,函数语言的let关键字) 。然后,您可以使用基本语法功能进一步缩小范围。
答案 14 :(得分:0)
我遇到的最佳解决方案是在Ruby on Rails应用程序中使用linguist gem。这是一种特定的方式,但它的工作原理。 @nisc上面提到了这一点,但我会告诉你我使用它的确切步骤。 (以下某些命令行命令特定于ubuntu,但应该很容易转换为其他操作系统)
如果你有任何你不介意暂时搞乱的rails应用程序,请在其中创建一个新文件以插入有问题的代码段。 (如果没有安装rails,那么有一个很好的指南here虽然对于ubuntu我推荐this。然后运行rails new <name-your-app-dir>
并进入该目录。运行rails app所需的一切已经存在了。)
使用rails应用程序后,将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>
)。它会告诉你类型,mime类型和语言。对于多个文件(或通常用于ruby / rails应用程序),您可以在应用程序的目录中运行bundle exec linguist --breakdown
。
这似乎是一项额外的工作,特别是如果你还没有轨道,但是你实际上并不需要知道关于rails的任何事情,如果你按照这些步骤而我真的没有找到更好的方法检测文件/代码段的语言。
答案 15 :(得分:0)
我认为没有单一的解决方案可以识别代码片段所使用的语言,仅基于该单个代码段。使用关键字print
。它可以以任意数量的语言出现,每种语言都有不同的用途,并且语法不同。
我确实有一些建议。我目前正在为我的网站编写一小段代码,用于识别编程语言。像大多数其他帖子一样,可能有一个巨大的范围的编程语言,你根本无法听到,你无法解释所有这些。
我所做的是可以通过选择关键字来识别每种语言。例如,可以通过多种方式识别Python。如果你选择“特质”,这可能会更容易。这也是该语言的独特之处。对于Python,我选择使用冒号来启动一组语句的特性,我认为这是一个相当独特的特性(如果我错了,请纠正我)。
如果在我的示例中,您无法找到冒号来启动语句集,那么请转到另一个可能的特征,让我们说使用def
关键字来定义函数。现在这会导致一些问题,因为Ruby也使用关键字def
来定义一个函数。告诉两者(Python和Ruby)的关键是使用各种级别的过滤来获得最佳匹配。 Ruby使用关键字end
来完成一个函数,而Python没有任何东西来完成一个函数,只是一个de-indent但你不想去那里。但同样,end
也可能是Lua,另一种编程语言可以添加到混合中。
您可以看到编程语言只是覆盖太多。一个关键字可能是一种语言的关键字,可能恰好是另一种语言的关键字。使用经常组合在一起的关键字组合,例如Java public static void main(String[] args)
有助于消除这些问题。
就像我已经说过的那样,你最好的机会是寻找相对独特的关键词或关键词组来将它们分开。并且,如果你弄错了,至少你有一个去。
答案 16 :(得分: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;
答案 17 :(得分:0)
如果您想以一种快速的方式将代码段粘贴到网络表单中,而不是通过编程的方式来进行操作,则该网站似乎非常擅长识别语言:http://dpaste.com/