我有一个包含一些文字的字符串。该文本可能是也可能不是代码。使用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
#!/usr/bin/env ruby
require 'linguist'
s = "int main(){}"
candidates = Linguist::Language.all
# I also tried only Popular
# candidates = Linguist.Language.popular
b = Linguist::Blob.new('', s)
langs = Linguist::Classifier.call(b, candidates)
puts langs.inspect
执行:
$ ./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>'
其他:
答案 0 :(得分:4)
快速浏览一下Linguist的源代码,它似乎使用了许多策略来确定语言,并依次调用每个策略。 Classifier
是最后一个被调用的策略,到那时它(希望)已经选择了语言&#34;候选人&#34; (正如您自己发现的那样)来自先前的策略。因此,我认为对于您与我们分享的特定样本,您必须传递某种文件名,即使文件实际上并不存在,也不得传递候选语言列表。如果两者都不是您的选择,这可能不是您的问题的可行解决方案。
$ ruby -r linguist -e 'p Linguist::Blob.new("foo.c", "int main(){}").language'
#<Linguist::Language name=C>
它返回nil
没有文件名,#<Linguist::Language name=C++>
返回&#34; foo.cc&#34;和相同的代码示例。
好消息是你挑选了一个非常糟糕的样本进行测试。 :-)其他策略着眼于模型和shebangs,因此更复杂的样本有更好的成功机会。看看这些:
$ ruby -r linguist -e 'p Linguist::Blob.new("", "#!/usr/bin/env perl
print q{Hello, world!};
").language'
#<Linguist::Language name=Perl>
$ ruby -r linguist -e 'p Linguist::Blob.new("", "# vim: ft=ruby
puts %q{Hello, world!}
").language'
#<Linguist::Language name=Ruby>
然而,如果没有一个shebang或一个模式,我们仍然没有运气。事实证明,有一个训练数据集在安装时被计算并序列化到磁盘,并在语言检测期间自动加载。不幸的是,我认为如果在进入此步骤时没有任何候选人,那么库中存在一个阻止使用此训练数据集的错误。修复错误让我这样做:
$ ruby -Ilib -r linguist -e 'p Linguist::Blob.new("", "int main(){}").language'
#<Linguist::Language name=XC>
(我不知道XC是什么,但是在#include <stdio.h>
或int argc, char* argv[]
这样的字符串中添加其他一些令牌会给出C.我确定你的大多数样本都会有更多的肉可以分析。)
这是一个非常简单的解决方案,我已经为它提交了PR。如果你愿意的话,你可以使用我的宝石叉。否则,我们需要直接使用Linguist :: Classify,因为您已经开始探索,但这有可能变得混乱。
要使用我的分支,请添加/修改您的Gemfile,如下所示:
gem 'github-linguist',
require: 'linguist',
git: 'https://github.com/mwpastore/linguist.git',
branch: 'fix-no-candidates'
当PR合并并且已经发布新版本的Gem时,我会尝试回来并更新此答案。如果我必须执行任何强制推送以满足存储库指南和/或使维护者满意,您可能必须执行bundler update
来反映更改。如果您有任何问题,请告诉我。
答案 1 :(得分:-1)
再看看语言学家的来源,Linguist::Language.all
似乎是你正在寻找的。 p>
编辑:我自己试过Linguist::Language.all
。失败是由于另一个错误:某些语言似乎有错误的数据。例如,这也失败了:
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] }