从片段中检测编程语言

时间:2009-01-23 23:16:31

标签: programming-languages language-detection

在一段代码中检测使用哪种编程语言的最佳方法是什么?

18 个答案:

答案 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,那么即使putsend是特定于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)

我认为语言之间最大的区别在于它的结构。所以我的想法是查看所有语言中的某些共同元素,看看它们有何不同。例如,您可以使用正则表达式来选择以下内容:

  • 功能定义
  • 变量声明
  • 类声明
  • 评论
  • for loops
  • while循环
  • print statements

也许还有其他大多数语言应该具备的东西。然后使用点系统。如果找到正则表达式,则每个元素最多奖励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 updatesudo apt-get install makesudo 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/