Lark грамматика: Как работает экранированное регулярное выражение строки? - PullRequest
2 голосов
/ 22 апреля 2020

Анализатор lark предопределяет некоторые общие терминалы, включая строку. Это определяется следующим образом:

_STRING_INNER: /.*?/
_STRING_ESC_INNER: _STRING_INNER /(?<!\\)(\\\\)*?/ 

ESCAPED_STRING : "\"" _STRING_ESC_INNER "\""

Я понимаю _STRING_INNER. Я также понимаю, как составляется ESCAPED_STRING. Но я не совсем понимаю, что это _STRING_ESC_INNER.

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

Как я могу объединить эти два в одно регулярное выражение?

И разве для грамматики не требуется разрешать только экранированные двойные кавычки в строковых данных?

1 Ответ

1 голос
/ 22 апреля 2020

Предварительные сведения:

  • .*? Нежадное совпадение, означающее наименьшее возможное количество повторений . (любой символ). Это имеет смысл только тогда, когда следует что-то еще. Таким образом, .*?X на входе AAXAAX будет соответствовать только части AAX, а не расширяться до последнего X.

  • (?<!...) является "отрицательным" утверждение с обратным указанием "( ссылка ):" Соответствует, если текущей позиции в строке не предшествует совпадение для .... ". Таким образом, .*(?<!X)Y будет соответствовать AY, но не XY.

Применение этого к вашему примеру:

  • ESCAPED_STRING: Правило гласит: «Совпадение ", затем _STRING_ESC_INNER, а затем " снова».

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

  • _STRING_ESC_INNER: мы хотим, чтобы это совпадало с максимально короткой строкой, которая не содержит закрывающей кавычки , То есть для ввода "abc"xyz" мы хотим соответствовать "abc", вместо того, чтобы потреблять часть xyz". Тем не менее, мы должны убедиться, что " действительно заключительная кавычка, так как она не должна быть сама по себе экранирована. Поэтому для ввода "abc\"xyz" мы не хотим сопоставлять только "abc\", потому что \" экранирован. Мы видим, что закрытию " должно предшествовать четное число \ (при этом ноль является четным числом). Итак, " в порядке, \\" в порядке, \\\\" в порядке и т.д. c. Но как только " предшествует нечетное число \, это означает, что " на самом деле не является заключительной кавычкой.

    (\\\\) соответствует \\. (?<!\\) говорит, что "позиция до этого не должна иметь \". Таким образом, объединенный (?<!\\)(\\\\) означает «соответствует \\, но только если ему не предшествует \».

    Следующий *? затем делает наименьшее возможное повторение этого, что опять же имеет смысл при рассмотрении следующего за ним регулярного выражения, которое является " из правила ESCAPED_STRING (возможная путаница: \" в ESCAPED_STRING относится к литералу " в фактическом вводе, который мы хотим чтобы соответствовать, так же, как \\\\ относится к \\ на входе). Таким образом, (?<!\\)(\\\\)*?\" означает «соответствовать кратчайшему количеству \\, за которым следует ", а не предшествует \. Другими словами, (?<!\\)(\\\\)*?\" соответствует только ", которому предшествует четное число \ (включая блоки размером 0).

    Теперь объединяя его с предшествующим _STRING_INNER, правило _STRING_ESC_INNER затем говорит: Сопоставьте first ", которому предшествует четное число \, то есть, другими словами, первый ", где \ сам по себе не экранирован.

...