Как лучше всего определить, какой язык программирования используется во фрагменте кода?
Как лучше всего определить, какой язык программирования используется во фрагменте кода?
Ответы:
Я думаю, что метод, используемый в спам-фильтрах, будет работать очень хорошо. Вы разбиваете фрагмент на слова. Затем вы сравниваете употребление этих слов с известными фрагментами и вычисляете вероятность того, что этот фрагмент написан на языке X для каждого интересующего вас языка.
http://en.wikipedia.org/wiki/Bayesian_spam_filtering
Если у вас есть базовый механизм, добавлять новые языки очень просто: просто обучите детектор с помощью нескольких фрагментов на новом языке (вы можете скормить ему проект с открытым исходным кодом). Таким образом, он узнает, что «System» может появиться во фрагментах кода C # и «положить» в фрагменты 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, потому что они всегда работают сами по себе.
Определение языка решено другими:
Подход Олоха: https://github.com/blackducksw/ohcount/
Подход Github: https://github.com/github/linguist
Вы можете найти полезный материал здесь: http://alexgorbatchev.com/wiki/SyntaxHighlighter . Алекс потратил много времени, выясняя, как анализировать большое количество разных языков и каковы ключевые элементы синтаксиса.
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 полностью запутал его, т. Е. Токенизатор чувствителен к пробелам. Как правило, простой подсчет хитов не кажется надежным. Более сильный синтаксический анализатор или, возможно, несовпадающее количество разделов могут работать лучше.
Во-первых, я бы попытался найти конкретные ключевые слова языка, например
"package, class, implements "=> JAVA
"<?php " => PHP
"include main fopen strcmp stdout "=>C
"cout"=> C++
etc...
Это будет зависеть от того, какой у вас тип фрагмента, но я бы пропустил его через серию токенизаторов и посмотрел, для какого языка BNF он подходит.
Хорошая головоломка.
Я думаю, что невозможно обнаружить все языки. Но вы можете запускать ключевые токены. (определенные зарезервированные слова и часто используемые комбинации символов).
Бен, есть много языков с похожим синтаксисом. Так что это зависит от размера сниппета.
Prettify - это пакет Javascript, который отлично справляется с определением языков программирования:
http://code.google.com/p/google-code-prettify/
В основном это подсветка синтаксиса, но, вероятно, есть способ извлечь часть обнаружения для определения языка из сниппета.
Мне это было нужно, поэтому я создал свой. https://github.com/bertyhell/CodeClassifier
Его очень легко расширить, добавив обучающий файл в нужную папку. Написано на C #. Но я полагаю, что код легко конвертируется на любой другой язык.
Я не думаю, что есть простой способ добиться этого. Я бы, вероятно, создал списки символов / общих ключевых слов, уникальных для определенных языков / классов языков (например, фигурные скобки для языка C-стиля, ключевые слова Dim и Sub для языков BASIC, ключевое слово def для Python, ключевое слово let для функциональных языков) . Тогда вы сможете использовать базовые синтаксические функции, чтобы еще больше сузить его.
Я думаю, что самое большое различие между языками - это их структура. Итак, моя идея состояла бы в том, чтобы посмотреть на определенные общие элементы во всех языках и увидеть, чем они отличаются. Например, вы можете использовать регулярные выражения для выделения таких вещей, как:
И, возможно, еще кое-что, что должно быть в большинстве языков. Тогда используйте балльную систему. Если регулярное выражение найдено, присудите не более 1 балла за каждый элемент. Очевидно, что в некоторых языках будет использоваться один и тот же синтаксис (циклы for часто пишутся так, for(int i=0; i<x; ++i)
чтобы каждый из нескольких языков мог получить балл за одно и то же, но, по крайней мере, вы уменьшаете вероятность того, что это будет совершенно другой язык). Некоторые из них могут получить 0 баллов по всем направлениям (например, фрагмент вообще не содержит функции), но это прекрасно.
Объедините это с решением Жюля, и оно должно работать хорошо. Может быть, также поищите частоту ключевых слов для дополнительного балла.
Интересный. У меня аналогичная задача по распознаванию текста в разных форматах. Свойства YAML, JSON, XML или Java? Например, даже с синтаксическими ошибками я должен с уверенностью отличать JSON от XML.
Я считаю, что то, как мы моделируем проблему, очень важно. Как сказал Марк, токенизация из одного слова необходима, но, вероятно, недостаточна. Нам понадобятся биграммы или даже триграммы. Но я думаю, что мы можем пойти дальше, зная, что мы смотрим на языки программирования. Я заметил, что почти в любом языке программирования есть два уникальных типа токенов - символы и ключевые слова . Символы относительно легко распознать (некоторые символы могут быть литералами, не являющимися частью языка). Тогда биграммы или триграммы символов подберут уникальные синтаксические структуры вокруг символов. Ключевые слова - еще одна легкая цель, если обучающая выборка достаточно велика и разнообразна. Полезной функцией могут быть биграммы вокруг возможных ключевых слов. Еще один интересный тип токена - пробел.. На самом деле, если мы токенизируем обычным способом через пробел, мы потеряем эту информацию. Я бы сказал, что для анализа языков программирования мы сохраняем маркеры пробелов, поскольку они могут нести полезную информацию о структуре синтаксиса.
Наконец, если я выберу классификатор, например случайный лес, я буду сканировать github и собирать весь общедоступный исходный код. Большая часть файла исходного кода может быть помечена суффиксом файла. Для каждого файла я случайным образом разделю его по пустым строкам на фрагменты разного размера. Затем я извлечу функции и обучу классификатор, используя помеченные фрагменты. После завершения обучения классификатор можно проверить на точность и отзывчивость.
Лучшее решение, с которым я столкнулся, - использование гема лингвиста в приложении Ruby on Rails. Это своего рода специфический способ сделать это, но он работает. Это было упомянуто выше @nisc, но я расскажу вам свои точные шаги по его использованию. (Некоторые из следующих команд командной строки специфичны для ubuntu, но должны быть легко переведены на другие ОС)
Если у вас есть какое-либо приложение rails, с которым вы не против временно возиться, создайте в нем новый файл, чтобы вставить рассматриваемый фрагмент кода. (Если у вас нет рельсы установлены там хороший гид здесь , хотя для убунту я рекомендую это . Затем запустите rails new <name-your-app-dir>
и перейдите в этот каталог. Все , что вам нужно запустить приложение рельсы уже есть).
После того, как у вас будет приложение 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
в каталоге вашего приложения.
Кажется, это требует много дополнительной работы, особенно если у вас еще нет рельсов, но на самом деле вам не нужно НИЧЕГО знать о рельсах, если вы выполните эти шаги, и я просто действительно не нашел лучшего способа обнаружить рельсы. язык файла / фрагмента кода.
Я считаю, что не существует единого решения, которое могло бы определить, на каком языке находится фрагмент, только на основе этого фрагмента. Возьмите ключевое слово print
. Он может появляться на любом количестве языков, каждый из которых предназначен для разных целей и имеет разный синтаксис.
У меня есть совет. В настоящее время я пишу небольшой фрагмент кода для своего веб-сайта, который можно использовать для определения языков программирования. Как и в большинстве других сообщений, может быть огромное количество языков программирования, о которых вы просто не слышали, вы не можете учесть их все.
Что я сделал, так это то, что каждый язык можно идентифицировать по набору ключевых слов. Например, Python можно идентифицировать несколькими способами. Вероятно, будет проще, если вы выберете «черты», которые также определенно уникальны для языка. Для Python я выбираю черту использования двоеточия для начала набора операторов, что, на мой взгляд, является довольно уникальной чертой (поправьте меня, если я ошибаюсь).
Если в моем примере вы не можете найти двоеточие для начала набора операторов, перейдите к другой возможной характеристике, скажем, используя def
ключевое слово для определения функции. Теперь это может вызвать некоторые проблемы, потому что Ruby также использует ключевое слово def
для определения функции. Ключом к различению этих двух (Python и Ruby) является использование различных уровней фильтрации для получения наилучшего соответствия. Ruby использует ключевое слово end
для завершения функции, тогда как Python не имеет ничего для завершения функции, только удаление отступа, но вы не хотите туда идти. Но опять же, это end
также может быть Lua, еще один язык программирования, который можно добавить.
Вы можете видеть, что языки программирования просто перекрывают друг друга. Одно ключевое слово, которое может быть ключевым словом на одном языке, может оказаться ключевым словом на другом языке. Использование комбинации ключевых слов, которые часто идут вместе, как в Java, public static void main(String[] args)
помогает устранить эти проблемы.
Как я уже сказал, ваш лучший шанс - это поиск относительно уникальных ключевых слов или наборов ключевых слов, чтобы отделить одно от другого. И, если вы ошиблись, по крайней мере, вы попробовали.
Этот сайт, кажется, довольно хорошо определяет языки, если вам нужен быстрый способ вставить фрагмент в веб-форму, а не делать это программно: http://dpaste.com/