Quick Links: Download Gideros Studio | Gideros Documentation | Gideros Development Center | Gideros community chat | DONATE
pattern matching question — Gideros Forum

pattern matching question

keszeghkeszegh Member
edited August 2022 in General questions
Hi guys, pattern matching is always a magic to me. I've wasted an hour on this issue, maybe you can solve faster:
given a string of the form:
number-spaces-number-spaces-number-optionalspaces-optionaltext(with possible spaces in it)
e.g.:
"100 100 60"
or
"60 250 80 this is it"

i want to extract the 3 numbers and the remainder as a string (or nil or "" it is is empty). what's the simplest way?
my best attempt so far:
string.match(text,"(%d*)%s*(%d*)%s*(%d*)%s?(.?*?)"))
which returns the numbers and the first letter of the remaining text. i don't understand why not all the remaining text though.

(i need this to read files in the gpl format, aka gimp palette)

Comments

  • btw i need the numbers as numbers and not as text, but i can convert them in a next step, so that's not an issue.
  • MoKaLuxMoKaLux Member
    edited August 2022
    here is a snipet from Gideros obj loader, maybe this can help?
    local function Split(str, delim, maxNb)
        -- Eliminate bad cases...
        if string.find(str, delim) == nil then return { str } end
    	if maxNb == nil or maxNb < 1 then
    		maxNb = 0 -- No limit
    	end
    	local result = {}
    	local pat = "(.-)" .. delim .. "()"
    	local nb = 0
    	local lastPos
    	for part, pos in string.gmatch(str, pat) do
    		if #part>0 then
    			nb = nb + 1
    			result[nb] = part
    			lastPos = pos
    			if nb == maxNb then break end
    		end
    	end
    	-- Handle the last field
    	if nb ~= maxNb then result[nb + 1] = string.sub(str, lastPos) end
    	return result
    end
    Then:
    	for line in io.lines(path.."/"..file) do
    		fld=Split(line," ",10)
    		for i=1,#fld,1 do fld[i]=string.gsub(fld[i], "\r", "") end
    		if (fld[2]~=nil) then fld[2]=string.gsub(fld[2], "\r", "") end
    		if fld[1]=="newmtl" then mtl={} mtls[prefix..fld[2]]=mtl
    		elseif fld[1]=="Kd" then mtl.kd={fld[2],fld[3],fld[4],1.0}
    		elseif fld[1]=="d" then mtl.kd[4]=fld[2] -- alpha XXX
    		elseif fld[1]=="map_Kd" then
    		...
    	end
    my growING GIDEROS github repositories: https://github.com/mokalux?tab=repositories
  • thanks, but reverse engineering such a code is what is especially painful for me. i was hoping that someone can tell me what is the few characters i need to change in my one line code so that it works as i want.
  • MoKaLuxMoKaLux Member
    edited August 2022
    The code reads each line and puts every "text" (separated by space " ") in a table.
    Then after that you can do whatever you like with the values (fld[1], fld[2], ...).
    fld=Split(line," ",10)
    for i=1,#fld,1 do fld[i]=string.gsub(fld[i], "\r", "") end
    if (fld[2]~=nil) then fld[2]=string.gsub(fld[2], "\r", "") end
    my growING GIDEROS github repositories: https://github.com/mokalux?tab=repositories
  • rrraptorrrraptor Member
    edited August 2022
    function split(str)
    	str = str:gsub("%s+"," ") -- transform any sequance of whitespace characters (tabs, spaces) to a single white space
     
    	-- empty string?
    	if str:len() == 0 then 
    		return {0, 0, 0}
    	end
     
    	local numbers, text = str:match("%s*([%d%s]*)(.*)") -- extract numbers and text
    	local color = numbers:split(" ") -- extract numbers as separated elements
     
    	-- convert string to number
    	for i = 1, 3 do 
    		color[i] = tonumber(color[i]) or 0
    	end
     
    	return color, text
    end
     
    local tests = {
    	"255	255		255		hello world",
    	"  10   10  10 some text here",
    	"nothing here...",
    	"10  10   10"
    }
     
    for i = 1, #tests do
    	local colors, text = split(tests[i])
    	print("Test #"..i)
    	print(colors[1])
    	print(colors[2])
    	print(colors[3])
    	print(text)
    end


    Pattern: https://regex101.com/r/RpwwBv/1

    Likes: MoKaLux

    +1 -1 (+1 / -0 )Share on Facebook
  • str:match("%s*([%d%s]*)(.*)") seems to split at the wrong place if the text contains numbers as well.
  • rrraptorrrraptor Member
    Accepted Answer
    @keszegh
    if there is only 3 numbers:
    function split(str)
    	str = str:gsub("%s+"," ")
     
    	if str:len() == 0 then 
    		return {0, 0, 0}
    	end
     
    	local r, g, b, text = str:match("%s*(%d*)%s*(%d*)%s*(%d*)%s*(.*)")
     
    	-- if there is no numbers (see test #4)
    	if r == '' then 
    		r = 0
    		g = 0
    		b = 0
    	else
    		r = tonumber(r)
    		g = tonumber(g)
    		b = tonumber(b)
    	end
     
    	return r, g, b, text
    end
     
    local tests = {
    	"255	255		255		hello world",
    	"  10   10  10 some text here",
    	"  10   10  10 text with numbers 123",
    	"nothing here...",
    	"10  10   10"
    }
     
    for i = 1, #tests do
    	local r,g,b, text = split(tests[i])
    	print("Test #"..i)
    	print(r,g,b)
    	print(text)
    	print(string.rep('-', 15))
    end

    Likes: keszegh

    +1 -1 (+1 / -0 )Share on Facebook
Sign In or Register to comment.