检测代码段中使用哪种编程语言的最佳方法是什么?
检测代码段中使用哪种编程语言的最佳方法是什么?
Answers:
我认为垃圾邮件过滤器中使用的方法效果很好。您将代码片段拆分为单词。然后,您可以将这些单词与已知代码段的出现情况进行比较,并针对您感兴趣的每种语言,计算此代码段以语言X编写的可能性。
http://en.wikipedia.org/wiki/Bayesian_spam_filtering
如果您具有基本的机制,那么添加新语言非常容易:只需用新语言的一些代码片段训练检测器(您可以将其提供给一个开源项目)。通过这种方式,它了解到“ System”很可能出现在C#代码片段中,而“ puts”可能出现在Ruby代码片段中。
实际上,我已经使用这种方法将语言检测添加到论坛软件的代码片段中。除有歧义的情况外,它100%的时间有效:
print "Hello"
让我找到代码。
我找不到代码,所以我做了一个新的代码。这有点简单,但适用于我的测试。当前,如果您提供的Python代码比Ruby代码多得多,则可能是这样的代码:
def foo
puts "hi"
end
是Python代码(尽管实际上是Ruby)。这是因为Python也有一个def
关键字。所以,如果它已经看到1000X def
在Python和100X def
在Ruby中那么它仍然可以说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完全混淆了它,即令牌生成器对空格敏感。通常,仅计算重点命中似乎不太可靠。更强大的解析器,或者可能是无与伦比的部分计数,可能会更好地工作。
Prettify是一个Javascript程序包,可以很好地检测编程语言:
http://code.google.com/p/google-code-prettify/
它主要是语法突出显示器,但是可能存在一种提取检测部分的方法,目的是从摘要中检测语言。
我需要这个,所以我创建了自己的。 https://github.com/bertyhell/CodeClassifier
通过在正确的文件夹中添加培训文件,可以很容易地扩展它。用C#编写。但我认为代码可以轻松转换为任何其他语言。
我认为语言之间的最大区别在于其结构。因此,我的想法是研究所有语言中的某些共同要素,并了解它们之间的差异。例如,您可以使用正则表达式来选择诸如:
也许大多数语言应该具备的其他一些功能。然后使用一个点系统。如果找到正则表达式,则对每个元素最多奖励1分。显然,某些语言将使用完全相同的语法(因为循环经常像for(int i=0; i<x; ++i)
这样编写,因此多种语言可以为同一事物得分,但是至少您要减少它成为完全不同的语言的可能性)。其中一些可能在整体上得分为0(例如,该代码段根本不包含任何功能),但是那很好。
将此与Jules的解决方案结合起来,它应该可以很好地工作。也许还会寻找关键词的频率来加分。
有趣。我有一项类似的任务,可以识别不同格式的文本。是YAML,JSON,XML还是Java属性?例如,即使存在语法错误,我也应该自信地将JSON与XML区别开。
我认为我们如何对问题建模是至关重要的。正如Mark所说,单字标记化是必要的,但可能还不够。我们将需要二元组,甚至三元组。但是我想知道我们正在研究编程语言,因此我们可以走得更远。我注意到几乎所有的编程语言都具有两种独特的令牌类型- 符号和关键字。符号相对容易识别(某些符号可能是文字,而不是语言的一部分)。然后,符号的双字母组或三字母组将围绕符号选取唯一的语法结构。如果培训足够大且足够多样化,则关键字是另一个容易的目标。一个有用的功能可能是围绕可能的关键字的双语法例。令牌的另一种有趣类型是空格。实际上,如果我们以通常的方式用空格标记,则会丢失此信息。我想说,在分析编程语言时,我们保留空白标记,因为这可能包含有关语法结构的有用信息。
最后,如果选择随机森林之类的分类器,则将爬网github并收集所有公共源代码。大多数源代码文件都可以用文件后缀标记。对于每个文件,我将在空行处将其随机分成各种大小的代码段。然后,我将提取特征并使用标记的片段来训练分类器。训练完成后,可以测试分类器的准确性和召回率。
我遇到的最好的解决方案是在Ruby on Rails应用程序中使用语言学家。这是一种特定的实现方式,但确实可行。@nisc在上面提到了这一点,但是我会告诉您我使用它的确切步骤。(以下某些命令行命令特定于ubuntu,但应轻松转换为其他操作系统)
如果您不介意暂时使用任何Rails应用程序,请在其中创建一个新文件以插入有问题的代码段。(如果您没有安装rails,这里有一个很好的指南,尽管对于ubuntu我还是推荐这样做。然后运行rails new <name-your-app-dir>
并cd进入该目录。运行rails应用程序所需的一切已经存在)。
使用了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>
)。它将告诉您类型,哑剧类型和语言。对于多个文件(或通常与ruby / rails应用程序一起使用),您可以bundle exec linguist --breakdown
在应用程序的目录中运行。
似乎需要做很多额外的工作,特别是如果您还没有Rails,但是如果按照以下步骤操作,实际上您不需要了解Rails的任何知识,而我只是真的没有找到更好的方法来检测文件/代码段的语言。
我认为,没有任何一种解决方案可以仅根据单个代码段来识别该代码段所使用的语言。拿关键字print
。它可以以多种语言出现,每种语言都有不同的用途,并且具有不同的语法。
我有一些建议。我目前正在为我的网站编写一小段代码,可用于识别编程语言。像大多数其他职位的,有可能是一个巨大的编程语言,你根本都没有听说过的范围内,你不能占他们所有。
我所做的是,可以通过选择关键字来识别每种语言。例如,可以通过多种方式来识别Python。如果您选择当然也是该语言特有的“特征”,则可能会更容易。对于Python,我选择使用冒号来启动一组语句的特征,我认为这是一个相当独特的特征(如果我错了,请纠正我)。
在我的示例中,如果找不到冒号来启动语句集,然后移至另一个可能的特征,则可以使用def
关键字定义函数。现在这可能会引起一些问题,因为Ruby还使用关键字def
定义了一个函数。区分两者(Python和Ruby)的关键是使用各种级别的过滤以获得最佳匹配。Ruby使用关键字end
来完成函数,而Python没有任何内容来完成函数,只是去缩进,但您不想去那里。但同样,end
也可以是Lua,这是另一种添加到其中的编程语言。
您会看到编程语言只是覆盖了太多。一个可能是一种语言的关键字的关键字可能恰好是另一种语言的关键字。使用经常组合在一起的关键字组合(例如Java)public static void main(String[] args)
有助于消除这些问题。
就像我已经说过的,您最好的机会是寻找相对独特的关键字或一组关键字,以将一个或另一个分隔开。而且,如果您弄错了,至少您可以尝试一下。
如果您想以一种快速的方式将摘要粘贴到Web表单中,而不是通过编程方式进行操作,则该站点似乎非常擅长识别语言:http : //dpaste.com/