Page 1 of 1
another problem with string pattern
Posted: Mon Apr 04, 2022 8:00 am
by Kavaline
Hi, I need help to find the pattern that have the wanted print output:
Code: Select all
str = "(1, 'test', none, 10, '', , 'hi, this is a default bio. change it (asap)!')"
for inf = 1, 9 do
pat = "%(" .. string.rep("%s?'?.-'?[,%)]+", inf - 1) .. "%s?'?(.-)'?[,%)]+"
result = str:match(pat)
print(result, "#" .. inf)
end
--Print result must be:
--1
--test
--none
--10
--
-- or nil
--hi, this is a default bio. change it (asap)!
--nil
--nil
The actual print result is:
1 #1
test #2
none #3
10 #4
#5
#6
hi #7
this is a default bio. change it (asap #8
! #9
I can't find a solution that if found a starting "'", ignores all rules until find a closing "'" and match a right pattern (a ", " or ")$")
Re: another problem with string pattern
Posted: Mon Apr 04, 2022 10:58 am
by ReFreezed
You cannot do this with a single pattern. You need different patterns for matching quoted and unquoted values. This also means you have to match one item at a time and choose the appropriate pattern dynamically.
Re: another problem with string pattern
Posted: Mon Apr 04, 2022 4:41 pm
by Kavaline
Ouch.. So, I'm thinking in something with another loop inside, counting the quotes to choose what pattern add to 'pat', I will scratch it later
Re: another problem with string pattern
Posted: Mon Apr 04, 2022 11:32 pm
by ReFreezed
No inner loops, counting of quotes, or generation of any pattern needed.
Code: Select all
local str = "(1, 'test', none, 10, '', , 'hi, this is a default bio. change it (asap)!')"
local items = {}
local pos = str:match("%(%s*()") or error("missing '('")
while true do
-- Match item.
local item
if str:sub(pos, pos) == "'" then
item, pos = str:match("^'(.-)'%s*()", pos) -- Quoted value.
assert(item, "missing end quote")
else
item, pos = str:match("^([^,)]*)()", pos) -- Unquoted value.
item = item:gsub("%s+$", "") -- Trim trailing spaces.
end
table.insert(items, item)
-- Continue or stop.
if str:sub(pos, pos) == "," then
pos = str:match("^,%s*()", pos) -- Continue loop.
elseif str:sub(pos, pos) == ")" then
break -- End of items.
else
error("expected ',' or ')' at position "..pos)
end
end
for i, item in ipairs(items) do
print("#"..i.." '"..item.."'")
end
--[[ Output:
#1 '1'
#2 'test'
#3 'none'
#4 '10'
#5 ''
#6 ''
#7 'hi, this is a default bio. change it (asap)!'
]]
Re: another problem with string pattern
Posted: Tue Apr 05, 2022 3:00 am
by Kavaline
But thanks to your direction, I did with them xD
Also, I will check your solution too, I didn't realize that I could use the () to get a string position, I tried something like this, but walked on other way because I couldn't find how to get the right positions. The way was, break the string after every match...
Code: Select all
str = "(1, 'test', none, 10, '', , 'hi, this is a default bio. change it (asap)!')"
s = str
result = {}
for inf = 1, 9 do
s = string.sub(s or "", math.min(2,s:len()))
if s:match("^'") then
result[inf] = s:match("%s?'(.-)'[,%)]+")
else
result[inf] = s:match("%s?(.-)[,%)]+")
end
s = s:match("^'?" .. string.rep(".", string.len(result[inf] or "")) .. "'?.?(.+)")
print(result[inf], "#" .. inf)
end
The only problem is that I can't get the exact info that I want; on my first try, I could get a Nth info directly, without a loop (thanks to string.rep). In this solutions, I always will read all infos in a loop, and after, get the one that I want. But if is the fastest way (and less headache), is this
Re: another problem with string pattern
Posted: Wed Apr 06, 2022 5:16 am
by Rigachupe
Or use a JSON library. The input string would change to:
local str = "{1, 'test', none, 10, '', , 'hi, this is a default bio. change it (asap)!'}"
And the output from JSON would be a table that you can traverse like an array.