Как я могу имитировать экранирующие символы в Lua? - PullRequest
0 голосов
/ 26 мая 2020

Я делаю синтаксический анализатор и хочу, чтобы входная строка поддерживала 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-символов, поэтому, если у кого-то есть лучшее решение, я был бы очень признателен!

...