-- Iterate over all items in `text`, use it like this :
-- options :
-- separator = "patern string" default "\n"
-- plain = boolean default nil for string.find
-- no_item = anything default nil, it's the return for previous_item [1] and next_item[last]
-- for item, state in TextIterator(s, { options }) do
-- -- item - contents without separator
-- -- state.item_num - number of the item, starting from 1
-- -- state.previous_item - the preceding item
-- -- state.next_item - the following item
-- -- state.separator - the matching separator
-- -- state.is_last - it's the last item
--end
local function TextIterator(s, options)
local options = options or {}
local state = {text = s, begin=1, next_begin=1,
item_num=-1, next_item=options.no_item, is_last=false}
local function get_item(state)
local text = state.text
state.begin = state.next_begin
state.previous_item = state.item
state.item = state.next_item
state.separator = state.next_separator
state.item_num = state.item_num + 1
if state.begin == -1 then
state.next_item = options.no_item
state.next_begin = -2
state.is_last = true
return state.item, state
elseif state.begin == -2 then
return nil
end
local b, e = text:find(options.separator,
state.next_begin, options.plain)
if b then
if options.plain then
state.next_separator = options.separator
else
state.next_separator = string.match(text,
"("..options.separator..")", state.next_begin)
end
state.next_begin = e+1
state.next_item = text:sub(state.begin,`enter code here`
e-string.len(state.next_separator))
return state.item, state
else
state.next_separator = ""
state.next_begin = -1
state.next_item = text:sub(state.begin)
return state.item, state
end
end
if not options.separator then options.separator = "\n" end
get_item(state) -- initialize
return get_item, state
end
txt = "a,b;c.d/e.f.g"
for item, state in TextIterator(txt, { separator="%p", plain=false, no_item=nil }) do
print(item, state.item_num, state.separator,
state.previous_item, state.next_item, state.is_last)
end
>lua -e "io.stdout:setvbuf 'no'" "txtiterator.lua"
a 1 , nil b false
b 2 ; a c false
c 3 . b d false
d 4 / c e false
e 5 . d f false
f 6 . e g false
g 7 f nil true
>Exit code: 0
\r
these days is a mere formality, imho. – Perfunctoryfor line in (s..'\n'):gmatch'(.-)\r?\n' do ... end
– Vagina