Я делаю синтаксический анализатор и хочу, чтобы входная строка поддерживала escape-символы, чтобы, например, если parse("Hello [world]")
давало: Hello world , тогда parse("Hello /[world]")
просто даст: Hello [world] . У меня есть реализация, которая работает, но сужает.
local function escapeStr(str)
local escapedStr = str:gsub("/(%[%])", "\1") -- for parsing
local regStr = str:gsub("/(%[%])", "%1") -- for displaying
return escapedStr, regStr
end
Эта функция создает 2 версии входной строки. Первый (escapedStr
) заменяет экранированный символ /[
пустым символом \1
. Это версия строки, которую использует синтаксический анализатор, которую я перебираю с помощью gmatch
, и она игнорирует специальные символы, потому что они были заменены на \1
. Затем во время итерации я использую regStr:sub(start, end)
, когда хочу извлечь подстроку, которая будет отображаться пользователю, поскольку regStr
- это то, как должна выглядеть экранированная строка при отображении, и regStr
и escapedStr
всегда имеют одинаковую длину.
Это решение ограничено тем, что для выполнения regStr:sub(start, end)
мне нужно отслеживать позицию в строке, когда я повторяю это, что не идеально в более сложных ситуациях. Здесь это не кажется таким уж плохим, например:
local str = "hello [world], wonderful day today"
local escapedStr, regStr = escapeStr(str)
for begin, stop in escapedStr:gmatch("()%[.-%]()") do
print(regStr:sub(begin, stop - 1)) --> [world]
end
... но это только потому, что я не сопоставляю ничего, кроме всего, что находится в квадратных скобках. Если бы я хотел сопоставить больше шаблонов в подстроке, мне пришлось бы добавить больше захватов в мой исходный строковый шаблон, который быстро вышел бы из-под контроля (беспорядочный / длинный).
for begin0, begin1, stop1, stop0 in escapedStr:gmatch("()%[%a+:()%a+()%]()") do
local entire_match = regStr:sub(begin0, stop0 - 1)
local second_match = regStr:sub(begin1, stop1 - 1)
print(entire_match) --> [world:earth]
print(second_match) --> earth
end
И в моем случае У меня много совпадений в подстроках, которые первоначально выбирает парсер, и я хотел бы сделать что-то вроде: "%[(.-)%]"
, чтобы вернуть нужные мне данные, а не "()%[.-%]()"
в паре с regStr:sub(start, end)
, чтобы выполнить sh то же самое .
Мне кажется, что я использую очень нетрадиционный способ реализации escape-символов, поэтому, если у кого-то есть лучшее решение, я был бы очень признателен!