2016-09-08 4 views
2

У меня есть строка, содержащая текст. Текст может быть или не быть кодом. Используя лингвиста Гитуба, я смог определить вероятный язык программирования, только если я дам ему список кандидатов.Как я могу определить язык программирования фрагмента?

# 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>' 

Дополнительно:

  1. Это лучший способ использовать GitHub Лингвист? FileBlob является альтернативой Blob, но для этого требуется записать мою строку в файл. Это проблематично по двум причинам: 1) он медленный, и 2) выбранное расширение файла затем лингвистическое руководство, и мы не знаем правильного расширения файла.
  2. Есть ли лучшие инструменты для этого? Github Linguist, возможно, работает над файлами, но не над строками.

ответ

3

Взяв быстрый взгляд на исходный код Linguist, он, по-видимому, использует ряд стратегий для определения языка, и он вызывает каждую стратегию в свою очередь. Classifier - последняя стратегия, которую нужно назвать, и к этому времени она (надеюсь) подобрала «кандидатов» языка (как вы сами поняли) из предыдущих стратегий. Поэтому я думаю, что для конкретного образца, который вы нам поделили, вам нужно передать какое-либо имя файла, даже если файл фактически не существует, или список кандидатов на язык. Если ни один из них не является для вас вариантом, это может оказаться нецелесообразным решением вашей проблемы.

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

Он возвращает nil без имени файла, и #<Linguist::Language name=C++> с «foo.cc» и того же образца кода.

Хорошей новостью является то, что вы выбрали очень плохой образец для тестирования. :-) Другие стратегии смотрят на моделины и 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> 

Однако, если это не притон или режимная, мы до сих пор не повезло. Оказывается, есть набор учебных материалов, которые вычисляются и сериализуются на диск во время установки и автоматически загружаются при обнаружении языка. К сожалению, я думаю, что в библиотеке есть ошибка, которая препятствует использованию этого набора данных обучения, если к тому времени, когда он дойдет до этого шага, нет кандидатов. Закрепление ошибка позволяет мне это сделать:

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

(я не знаю, что Хс, но с добавлением некоторых других маркеров в строку, такие как #include <stdio.h> или int argc, char* argv[] дает C. Я уверен, что большинство из ваших образцов будет есть больше мяса для анализа.)

Это простое исправление, и я представил для него PR. Вы можете использовать мою вилку Gem, если хотите, тем временем.В противном случае нам нужно будет изучить использование Linguist :: Classify напрямую, как вы начали изучать, но это может стать бесполезным.

Чтобы использовать вилку, добавить/изменить ваш Gemfile читать как таковой:

gem 'github-linguist', 
    require: 'linguist', 
    git: 'https://github.com/mwpastore/linguist.git', 
    branch: 'fix-no-candidates' 

Я постараюсь вернуться и обновить этот ответ, когда PR был объединен и новую версию Gem был выпущен с исправлением. Если мне нужно сделать какие-либо принудительные нажатия для соответствия рекомендациям репозитория и/или сделать счастливыми сопровождающих, вам может понадобиться сделать bundler update, чтобы отразить изменения. Дайте знать, если у вас появятся вопросы.

+0

Спасибо за ответ. Однако, как я упоминаю в вопросе, я знаю расширение файла, потому что я не знаю языка программирования. Я пытаюсь обнаружить (вероятный) язык программирования. –

+0

@MartinVelez А, я вижу это сейчас. Виноват. Позвольте мне пообщаться с ним немного больше. – mwp

+0

@MartinVelez Я думаю, вы нашли ошибку в драгоценности. :-) Я представил PR и задокументировал, как вы можете использовать свою вилку. Пожалуйста, поделись своими мыслями. – mwp

-1

Взяв еще один быстрый взгляд на источник лингвиста, Linguist::Language.all, похоже, то, что вы ищете.

EDIT: Пробовал 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] } 
+0

спасибо! Я попробовал это. Это не работает. См. Возникшую ошибку. –

+0

Стратегии выбора лингвистов (будь то байесовский классификатор или эвристические правила) не были созданы, чтобы выбрать язык среди всех возможных языков. Это всего лишь утонченные стратегии. Если вы попытаетесь использовать их со всеми языками в качестве входных данных, скорее всего, вы получите очень плохие результаты. – pchaigno

+0

@pchaigno: Итак? Вопрос: «Как я могу избежать определения списка кандидатов?», И ответ ответил на него (в то время я не смотрел, продолжает ли он или нет). Совершенно необязательно откладывать отказ от ответственности «если вы уберете некоторые из методов, которые мы используем для повышения точности классификации, точность классификации может пострадать». – Amadan

Смежные вопросы