Я бы сказал, не поймите исключение, если вы действительно не можете справиться с этим. И регистрация не считается обработкой ошибки. Лучше подать это кому-нибудь, кто может, бросив исключение.
Если вы должны вернуть значение, а null - единственная разумная вещь, в этом нет ничего плохого. Просто документируйте это и проясните пользователям, что должно быть сделано. Проведите модульное тестирование, которое показывает, что генерируется исключение, чтобы разработчики пришли после того, как вы увидите, какой должна быть принятая идиома. Он также проверит, чтобы убедиться, что ваш код генерирует исключение, когда это необходимо.
Я думаю, вам никогда не следует полагаться на одну-единственную функцию, поскольку ее отсутствие во фрагменте (например, кто-то систематически использует WHILE вместо for) может вас смутить.
Также старайтесь держаться подальше от глобальных идентификаторов, таких как «ИМПОРТ», «МОДУЛЬ», «ЕДИНИЦА» или «ИНИЦИАЛИЗАЦИЯ / ФИНАЛИЗАЦИЯ», поскольку они могут не всегда существовать, быть необязательными в полных источниках и полностью отсутствовать во фрагментах.
Диалекты и подобные языки (например, Modula2 и Pascal) тоже опасны.
Я бы создал простые лексеры для ряда языков, которые отслеживают ключевые токены, а затем просто вычислил бы соотношение ключевых токенов к "другим" идентификаторам. Присвойте каждому токену вес, поскольку некоторые из них могут быть ключевым показателем для устранения неоднозначности между диалектами или версиями.
Vim has a autodetect filetype feature. If you download vim sourcecode you will find a /vim/runtime/filetype.vim file.
For each language it checks the extension of the file and also, for some of them (most common), it has a function that can get the filetype from the source code. You can check that out. The code is pretty easy to understand and there are some very useful comments there.
Very interesting question, I don't know if it is possible to be able to distinguish languages by code snippets, but here are some ideas:
:=
. Pascal has many unique keywords, too (begin, sub, end, ...)max()
, for example)#define boolean int
) So you can never guarantee, that you found the correct language.token_get_all()
for PHP - or third-party tools - like pychecker for python - to check the syntaxSumming it up: This project would make an interesting research paper (IMHO) and if you want it to work well, be prepared to put a lot of effort into it.
Самый надежный, но и самый трудоемкий способ - написать синтаксический анализатор для каждого языка и просто запустить их последовательно, чтобы увидеть, какой из них примет код. Это не сработает, если в коде есть синтаксические ошибки, и вам, скорее всего, придется иметь дело с таким кодом, люди действительно делают ошибки. Один из быстрых способов реализовать это - получить общие компиляторы для каждого поддерживаемого вами языка, просто запустить их и проверить, сколько ошибок они выдают.
Эвристика работает до определенного момента, и чем больше языков вы будете поддерживать, тем меньше помощи вы бы получили от них. Но для первых нескольких версий это хорошее начало, в основном потому, что оно быстро реализуется и в большинстве случаев работает достаточно хорошо. Вы можете проверить конкретные ключевые слова, имена функций / классов в API, которые часто используются, некоторые языковые конструкции и т. Д.
Как насчет частотного анализа слов (с изюминкой)? Анализируйте исходный код и классифицируйте его так же, как это делает спам-фильтр. Таким образом, когда в ваше приложение вводится фрагмент кода, который не может быть идентифицирован на 100%, вы можете указать ему наиболее близкие совпадения, из которых пользователь может выбрать - затем его можно будет ввести в вашу базу данных.
One program I know which even can distinguish several different languages within the same file is ohcount. You might get some ideas there, although I don't really know how they do it.
In general you can look for distinctive patterns:
:=
for Pascal/Modula/Oberon, =>
or the whole of LINQ in C#You may create a set of rules, each of which indicates a possible set of languages if it matches. Intersecting the resulting lists will hopefully get you only one language.
The problem with this approach however, is that you need to do tokenizing and compare tokens (otherwise you can't really know what operators are or whether something you found was inside a comment or string). Tokenizing rules are different for each language as well, though; just splitting everything at whitespace and punctuation will probably not yield a very useful sequence of tokens. You can try several different tokenizing rules (each of which would indicate a certain set of languages as well) and have your rules match to a specified tokenization. For example, trying to find a single-quoted string (for trying out Pascal) in a VB snippet with one comment will probably fail, but another tokenizer might have more luck.
But since you want to perform analysis anyway you probably have parsers for the languages you support, so you can just try running the snippet through each parser and take that as indicator which language it would be (as suggested by OregonGhost as well).
Some thoughts:
$x->y() would be valid in PHP, so ensure that there's no $ symbol if you think C++ (though I think you can store function pointers in a C struct, so this could also be C).
public static void main
is Java if it is cased properly - write Main and it's C#. This gets complicated if you take case-insensitive languages like many scripting languages or Pascal into account. The [] attribute syntax in C# on the other hand seems to be rather unique.
You can also try to use the keywords of a language - for example, Option Strict
or End Sub
are typical for VB and the like, while yield
is likely C# and initialization
/implementation
are Object Pascal / Delphi.
If your application is analyzing the source code anyway, you code try to throw your analysis code at it for every language and if it fails really bad, it was the wrong language :)
Вот вам идея. Для каждого из ваших N языков найдите несколько файлов на этом языке, чего-то вроде 10-20 на каждый язык будет достаточно, каждый не слишком короткий. Объедините все файлы на одном языке вместе. Назовите это lang1.txt. Заархивируйте его на lang1.txt.gz. У вас будет набор из N файлов langX.txt и langX.txt.gz.
Теперь возьмите нужный файл и добавьте его к каждому из файлов langX.txt, создав langXapp.txt и соответствующий сжатый langXapp.txt. .gz. Для каждого X найдите разницу между размером langXapp.gz и langX.gz. Наименьшая разница будет соответствовать языку вашего файла.
Отказ от ответственности: это будет работать достаточно хорошо только для более длинных файлов. Кроме того, это не очень эффективно. Но с другой стороны, вам не нужно ничего знать о языке, это полностью автоматически. И он может обнаруживать естественные языки и различать французский или китайский. На всякий случай :) Но основная причина, я просто думаю, что попробовать интересно :)
I think the problem is impossible. The best you can do is to come up with some probability that a program is in a particular language, and even then I would guess producing a solid probability is very hard. Problems that come to mind at once:
Those seem enough problems to solve to be going on with.
создайте общий токенизатор и затем примените к нему байесовский фильтр. Используйте существующую систему «пользователь ставит отметку» для его обучения.
Мой подход был бы следующим:
Создайте список строк или регулярных выражений (с и без учета регистра), где каждому элементу присвоен список языков, для которых этот элемент является индикатором:
и т. Д. Затем проанализируйте файл построчно, сопоставьте каждый элемент списка и посчитайте совпадения.
Выигрывает язык с наибольшим количеством совпадений;)
В ответ на 2: если есть "#!" и имя переводчика в самом начале, тогда вы точно знаете, на каком языке. (Не могу поверить, что об этом никто не упомянул.)
Невозможно сделать это надежным, но я бы лично начал с операторов, поскольку они в большинстве случаев «высечены в камне» (я не могу сказать, что это верно для каждого языка так как знаю только ограниченный набор). Это могло бы значительно сузить круг, но не достаточно. Например, "->" используется во многих языках (по крайней мере, C, C ++ и Perl).
Я бы сделал что-то вроде этого:
Создайте список функций для каждого языка, это могут быть операторы, комментирующие стиль (поскольку большинство из них используют какой-либо легко обнаруживаемый символ или комбинацию символов).
Например: В некоторых языках есть строки, начинающиеся с символа «#», например C, C ++ и Perl. Используют ли в своем словаре другие люди, кроме первых двух, #include и #define? Если вы обнаружите этот символ в начале строки, язык, вероятно, один из них. Если символ находится в середине строки, язык, скорее всего, Perl.
Кроме того, если вы найдете шаблон: =, это сузит его до некоторых возможных языков.
И т.д.
Я бы сделал это. иметь двумерную таблицу с найденными языками и шаблонами, и после анализа я просто подсчитываю, какой язык имеет больше всего "хитов". Если бы я хотел, чтобы это было действительно умно, я бы дал каждой функции вес, который означал бы, насколько вероятно или маловероятно, что эта функция будет включена в фрагмент этого языка. Например, если вы можете найти фрагмент, который начинается с / * и заканчивается на * /, более чем вероятно, что это либо C, либо C ++.
Проблема с ключевыми словами заключается в том, что кто-то может использовать его как обычную переменную или даже внутри Комментарии. Их можно использовать в качестве решающих (например, слово «класс» гораздо более вероятно в C ++, чем в C, если все остальное равно), но вы не можете полагаться на них.
После анализа я бы предложил наиболее вероятное язык как выбор для пользователя с упорядоченным остальным, который также может быть выбран. Таким образом, пользователь согласится с вашим предположением, просто нажав кнопку, или он может легко переключить его.
гораздо более вероятно в C ++, чем в C, если все остальное равно), но вы не можете полагаться на них.После анализа я бы предложил наиболее вероятный язык в качестве выбора для пользователя с упорядоченным остальным, который также быть выбираемым. Таким образом, пользователь согласится с вашим предположением, просто нажав кнопку, или он может легко переключить его.
гораздо более вероятно в C ++, чем в C, если все остальное равно), но вы не можете полагаться на них.После анализа я бы предложил наиболее вероятный язык в качестве выбора для пользователя с упорядоченным остальным, который также быть выбираемым. Таким образом, пользователь согласится с вашим предположением, просто нажав кнопку, или он может легко переключить его.
Вот простой способ сделать это. Просто запустите парсер на каждом языке. Независимо от того, какой язык продвинется дальше всех без ошибок (или имеет наименьшее количество ошибок), побеждает.
Этот метод имеет следующие преимущества: