Как разобрать ~{expr} внутри строки с помощью lark ebnf

Я пытаюсь написать грамматику Lark для DSL, но возникают проблемы с синтаксисом интерполяции строки:

" abc " <- normal string
" xyz~{expression}abc " <- string with interpolation

поэтому ~{переключается со строки на выражение, а} завершает это выражение. Я думаю, что это близко

string : "\"" (string_interp|not_string_interp)* "\""
string_interp: "~{" expression "}"
not_string_interp: /([^~][^{])+/

Но регулярное выражение будет соответствовать только четному количеству символов, и если ~{перекрывает четную границу, оно будет пропущено.

not_string_interp: /(.?|([^~][^{])+)/

Это примерно так, как я мог бы получить, но все еще кажется неправильным. Могу ли я использовать Lookaheads? Я также хочу, чтобы% игнорировал WS, так как он сильно подавляет шум, поэтому решение, учитывающее это, было бы замечательно!

Спасибо

Тестовые случаи:

""
"a"
"~{1}"
" ~{1} "
"a bc~{1}c d"
"a b~{1}c d"

2 ответа

Решение

Я думаю, что это делает это. К сожалению, любой ~, за которым не следует {, разделит строку, но я могу восстановить их позже. Меня вводят в заблуждение равный приоритет правил и жадность регулярных выражений.

/[^"~]+/ все, что не ~ или " (обычная строка)

"~{" expression "}" нормальное выражение

/~(?!{)/ обрабатывать ~ без {. Используйте? потому что мы не должны потреблять следующий символ (это может быть "или другой ~)

from lark import Lark

print (Lark(r"""
    string: "\"" string_thing* "\""
    string_thing: /[^"~]+/
        | "~{" expression "}"
        | /~(?!{)/
    expression: /[^}]+/
""", start='string', ambiguity="explicit").parse(
# '"a"'
'"a~b{}c}d~{1}g"'
# '"~abc~"'
# '"~{1}~~{1}~~~{1}"'
).pretty())

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

(?<=~{)[^}]+

Выглядит начало выражения ~{ и захватывает все до закрывающей скобки }

Другие вопросы по тегам