В луях прост есть шаблончик сбалансированной фигни, типа %b.
Применяется на манер
str = "скобки ( фигня (и тут скобок) чутка) бла"
=str:match("%b()")
>( фигня (и тут скобок) чутка)
Но оно работает только с одиночными символами, то есть мы не можем туда загнать что-то полноценное типа тегов или, тем более, регулярок.
Ну кароч примерно вот так.
local huge, min = math.huge, math.min
local function string_bfind(str, head, tail, offset, ex_bounds, plain)
local header_start, header_end = str:find(head, offset or 1, plain)
if not header_start then return nil end
local cursor = header_end
local last_tail_start = 0
local counter = 1
while counter > 0 do
local ha, hb = str:find(head, cursor + 1, plain)
if not ha then ha, hb = huge, huge end
local ta, tb = str:find(tail, cursor + 1, plain)
if not ta then return nil end
counter = counter + (ha < ta and 1 or -1)
cursor = min(hb, tb)
last_tail_start = ta
end
if ex_bounds then
local a, b = header_end + 1, last_tail_start - 1
return str:sub(a, b), a, b
end
return str:sub(header_start, cursor), header_start, cursor
end
local str = "<html><div><div></div><span/></div></html>"
print(string_bfind(str, "<div>", "</div>") )
Тупой подсчёт вхождений, но фичеватость присутствует. Можно ещё оптимизировать на пару курсоров, чтобы не переискивало каждый раз начало и конец, но пока впадлу.