Когда я должен использовать парсер? - PullRequest
8 голосов
/ 11 апреля 2009

В Regexes возникли проблемы с разделением кода на функциональные компоненты. Они могут сломаться или это может занять много времени, чтобы закончить. Опыт поднимает вопрос:

«Когда мне использовать парсер?»

Ответы [ 8 ]

9 голосов
/ 11 апреля 2009

Вы должны использовать парсер, если вас интересует лексическое или семантическое значение текста , когда шаблоны могут различаться. Парсеры, как правило, излишни, когда вы просто хотите сопоставить или заменить шаблоны символов , независимо от их функционального значения.

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


Однако парсер не означает автоматически, что он должен быть сложным. Например, если вас интересуют блоки кода на языке C, вы можете просто проанализировать вложенные группы {и}. Этот синтаксический анализатор будет интересоваться только двумя токенами ('{' и '}') и блоками текста между ними.

Однако простого сравнения регулярных выражений здесь недостаточно из-за вложенной семантики. Возьмите следующий код:

void Foo(bool Bar)
{
    if(Bar)
    {
        f();
    }
    else
    {
        g();
    }
}

Парсер будет понимать общую область видимости Foo, а также каждую внутреннюю область видимости, содержащуюся в Foo (блоки if и else). По мере того, как он встречает каждый знак «{», он «понимает» их значение. Простой поиск, однако, не понимает смысла текста и может интерпретировать следующее как блок, который, конечно, мы знаем, неверен:

{
    if(Bar)
    {
        f();
    }
3 голосов
/ 11 апреля 2009

вам нужен парсер, когда:

  1. язык не обычный ( википедия )
  2. вам нужно дерево разбора (в более общем случае, когда вам нужно выполнить действия контекстуально)
  3. когда полученное регулярное выражение слишком неясное / сложное

Мои 2 цента.

2 голосов
/ 13 апреля 2009

Книга Дракона имеет небольшой раздел о том, что вы не можете использовать Регулярные выражения для:

  • Они не могут обнаружить повторение строки, что означает, что вы не можете сопоставить конструкции типа 'wcw', где w - это та же последовательность символов
  • Вы можете обнаружить только фиксированное количество повторений или неопределенное количество повторений, то есть вы не можете использовать уже проанализированный токен для определения количества повторений, что-то вроде: 'n s1 s2 ... sn «
  • «Регулярные выражения не могут использоваться для описания сбалансированных или вложенных конструкций, [как] набор строк всех сбалансированных скобок»

Для 1 и 2 есть простое объяснение, вы не можете захватить подстроку, чтобы вы могли сопоставить ее позже. Если бы вы были, чем вы бы использовали парсер. Подумайте, как бы вы использовали регулярные выражения для этих случаев, и вы интуитивно придете к выводу, что не можете. :)

Для 3 это то же самое, что и проблема в K & R для разбора строковых литералов. Вы не можете просто сказать, что строковый литерал находится между первым "" "и вторым" ", но что происходит, когда есть экранированная кавычка (\")?

Что касается отношения к парадоксу Рассела, я думаю, вы правы, потому что проблема в ограниченных возможностях самоанализа regex. В книге есть ссылки на доказательства. Если хотите, я могу найти их для вас.

2 голосов
/ 11 апреля 2009

Существует несколько убедительных вариантов использования синтаксических анализаторов над регулярными выражениями. Вы должны использовать парсер вместо регулярного выражения:

  • Всякий раз, когда вы хотите работать с выражениями, которые являются более сложными, чем несколько семантических объектов (теги, переменные, номера телефонов и т. Д.).
  • Всякий раз, когда вам нужно знать семантическое значение текста вместо простого сопоставления с шаблоном. Например, если вы пытаетесь сопоставить все возможные способы написания телефонного номера, парсер, вероятно, лучше, чем регулярное выражение. Если вы пытаетесь сопоставить конкретный шаблон, который соответствует номеру телефона, регулярное выражение, вероятно, подойдет.
  • Всякий раз, когда невозможно гарантировать правильность ввода,
  • Если вы работаете полностью в структуре четко определенного языка, имеющего синтаксическую спецификацию (C #, XML, C ++, Ruby и т. Д.), То уже будет парсер, так что вам нужно поработать для вас.
1 голос
/ 11 апреля 2009

Вот некоторые примеры использования, предоставленные Стивом Йегге: Rich Programmer Food

1 голос
/ 11 апреля 2009

Вам нужно использовать парсер, как только у вас возникнет проблема, которую регулярные выражения не предназначены (или просто не могут) решить. Например, сопоставление (не) сбалансированных скобок (рекурсивно) является одной из таких проблем. Несмотря на то, что некоторые разновидности, такие как PCRE, дают вам очень далеко, они не выигрывают над парсером, написанным от руки.

0 голосов
/ 13 апреля 2009

Есть вещи, которые регулярное выражение не может сделать, в то время как синтаксический анализатор может.
Например:

Start :: = (Inner);
Внутренний :: = Старт | х;

Регулярное выражение не сможет этого сделать, потому что регулярное выражение не может отследить, если есть одинаковое количество открытых и закрытых скобок. Вот почему, когда вы пытаетесь токенизировать и анализировать большой файл, ожидается использование синтаксического анализатора, в то время как регулярное выражение может просто найти специальные шаблоны внутри файла.

0 голосов
/ 11 апреля 2009

Ваш вопрос немного расплывчат, но я думаю, что мое мнение таково, что когда ваше регулярное выражение усложняется или занимает слишком много времени, и у вас есть разумно определенный "язык", с которым нужно иметь дело, анализатор будет проще.

Я не думаю, что вы можете установить линию на песке и сказать, что все с одной стороны может быть сделано с помощью регулярных выражений, а с другой стороны вам нужен парсер. Это зависит от ситуации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...