Ruby 如何检测代码段的编程语言?

Ruby 如何检测代码段的编程语言?,ruby,github-linguist,Ruby,Github Linguist,我有一个包含一些文本的字符串。文本可能是代码,也可能不是代码。使用Github的语言学家,我只有在给出候选语言列表的情况下才能检测出可能的编程语言 # test_linguist_1.rb #!/usr/bin/env ruby require 'linguist' s = "int main(){}" candidates = [Linguist::Language["Python"], Linguist::Language["C"], Linguist::Language["Ruby"]

我有一个包含一些文本的字符串。文本可能是代码,也可能不是代码。使用Github的语言学家,我只有在给出候选语言列表的情况下才能检测出可能的编程语言

# test_linguist_1.rb
#!/usr/bin/env ruby

require 'linguist'

s = "int main(){}"
candidates = [Linguist::Language["Python"], Linguist::Language["C"], Linguist::Language["Ruby"]]
b = Linguist::Blob.new('', s)
langs = Linguist::Classifier.call(b, candidates)
puts langs.inspect
执行:

$ ./test_linguist_1.rb 
[#<Linguist::Language name=C>, #<Linguist::Language name=Python>, #<Linguist::Language name=Ruby>]
$ ./test_linguist_2.rb 
/home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:131:in `token_probability': undefined method `[]' for nil:NilClass (NoMethodError)
from /home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:120:in `block in tokens_probability'
from /home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:119:in `each'
from /home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:119:in `inject'
from /home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:119:in `tokens_probability'
from /home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:105:in `block in classify'
from /home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:104:in `each'
from /home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:104:in `classify'
from /home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:78:in `classify'
from /home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:20:in `call'
from ./test_linguist.rb:21:in `block in <main>'
from ./test_linguist.rb:14:in `each'
from ./test_linguist.rb:14:in `<main>'
执行:

$ ./test_linguist_1.rb 
[#<Linguist::Language name=C>, #<Linguist::Language name=Python>, #<Linguist::Language name=Ruby>]
$ ./test_linguist_2.rb 
/home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:131:in `token_probability': undefined method `[]' for nil:NilClass (NoMethodError)
from /home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:120:in `block in tokens_probability'
from /home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:119:in `each'
from /home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:119:in `inject'
from /home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:119:in `tokens_probability'
from /home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:105:in `block in classify'
from /home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:104:in `each'
from /home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:104:in `classify'
from /home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:78:in `classify'
from /home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:20:in `call'
from ./test_linguist.rb:21:in `block in <main>'
from ./test_linguist.rb:14:in `each'
from ./test_linguist.rb:14:in `<main>'
$。/test\u语言学家\u 2.rb
/home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:131:in'token_probability':nil:NilClass的未定义方法“[]”(NoMethodError)
from/home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:120:in `标记块中的概率'
from/home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:119:in'each'
from/home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:119:in'inject'
from/home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:119:in'tokens\u probability'
from/home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:105:在“分类中的块”中
from/home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:104:in'each'
from/home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:104:in“分类”
from/home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:78:in“分类”
from/home/marvelez/.rvm/gems/ruby-2.2.1/gems/github-linguist-4.8.9/lib/linguist/classifier.rb:20:in'call'
from./test_语言学家。rb:21:in'block in'
from./test_语言学家。rb:14:in'each'
来自./test_语言学家。rb:14:in`'
其他:

  • 这是使用Github语言学家的最佳方式吗?FileBlob是Blob的替代品,但这需要将我的字符串写入文件。这是有问题的,原因有两个:1)速度慢,2)选择的文件扩展名指导语言学家,我们不知道正确的文件扩展名
  • 是否有更好的工具来实现这一点?Github语言学家也许可以很好地处理文件,但不能处理字符串

  • 快速查看一下语言学家的源代码,它似乎使用了许多策略来确定语言,并依次调用每个策略<代码>分类器是最后一个被调用的策略,到那时它(希望)已经从先前的策略中选择了语言“候选者”(正如您自己所发现的)。因此,我认为对于您与我们共享的特定示例,您必须传递某种文件名,即使文件实际上不存在,或语言候选列表。如果两者都不是你的选择,这可能不是解决你问题的可行方案

    $ ruby -r linguist -e 'p Linguist::Blob.new("foo.c", "int main(){}").language'
    #<Linguist::Language name=C>
    
    然而,如果没有shebang或modeline,我们仍然运气不佳。事实证明,有一个训练数据集在安装时被计算并序列化到磁盘,并在语言检测期间自动加载。不幸的是,我认为库中有一个bug,它阻止了这个训练数据集在到达这个步骤之前没有任何候选数据集的情况下被使用。修复此错误使我可以执行以下操作:

    $ ruby -Ilib -r linguist -e 'p Linguist::Blob.new("", "int main(){}").language'
    #<Linguist::Language name=XC>
    

    我会尝试回来,并更新这个答案时,公关已经合并,一个新版本的创业板已经发布了修复。如果我必须执行强制推送以满足存储库指南和/或使维护人员满意,您可能必须执行
    绑定器更新
    ,以反映更改。如果您有任何问题,请告诉我。

    再快速查看一下语言学家源代码,
    语言学家::Language。所有的
    似乎都是您想要的

    编辑:尝试了
    语言学家::语言。所有人都是我自己。失败是由于另一个错误:一些语言似乎有错误的数据。例如,这也会失败:

    candidates = [Linguist::Language['ADA']]
    
    这显然是因为在
    lib/linguist/samples.json
    中,
    tokens.ADA
    不存在。这不是唯一一种这样的语言

    为了避免该错误,您可以过滤以下语言:

    non_buggy_languages = Linguist::Samples.cache['tokens'].keys
    candidates = non_buggy_languages.map { |l| Linguist::Language[l] }
    

    谢谢你的回答。但是,正如我在问题中提到的,我知道文件扩展名,因为我不知道编程语言。我正在尝试检测(可能的)编程语言。@MartinVelez啊,我现在明白了。我的错误。让我再修改一下。@MartinVelez我想你在宝石里发现了一个bug。:-)我已经提交了一份PR,并记录了如何使用我的叉子。请告诉我你的想法。@MartinVelez:文件扩展名并不是检测编程语言的可靠来源。例如,在用Perl、Python、Ruby和shell语言编写可执行脚本(而不是库)时,通常不使用任何扩展名。xC是一种用于并行实时嵌入式编程的语言,集成了Occam-π和C中的元素。您使用的代码段恰好是一个完整有效的xC程序。这也是一个完整有效的旋风计划。一个完整有效的Objul-C++、Objul-C、C++、D程序。正如你所说,程序越长,语言就越有可能是独一无二的。但是仍然:Objective-C是C的一个适当超集,因此所有C程序也都是Objective-C程序,例如。谢谢!我试过了。它不起作用。查看触发的错误。语言学家的选择策略(可能是贝叶斯分类器或启发式规则)不是为了在所有可能的语言中选择一种语言而建立的。它们只是改进策略。如果您试图将它们与所有语言一起用作输入,您很可能会得到非常糟糕的结果。@pchaigno:那么?问题是“我如何才能避免定义候选人名单?”,答案回答了这个问题(当时,我还没有看它是否仍然存在)。我不同意这样的说法:“如果你拿走了我们用来提高分类准确度的一些方法,分类准确度可能会受到影响。”。阅读你答案的人可能会认为语言学家并没有这样做
    non_buggy_languages = Linguist::Samples.cache['tokens'].keys
    candidates = non_buggy_languages.map { |l| Linguist::Language[l] }