String to table help

Im trying to serialize a table to a string, save in project data, then rebuild the table using the saved data when reset.
Ive serialized and saved but im not sure how to change it back, somesort of loop maybe?
Heres my example:

function setup()
    parameter.watch("a") parameter.watch("b")
 -- t = {{200,199},{933,188}}
    t = {}
    str = "{200,199},{933,188}"
    start = 1 -- en + 2 ? 11

    st = string.find(str,"{",start) -- start 
    cm = string.find(str,",",start) -- comma
    en = string.find(str,"}",start) -- end

    a = string.sub(str,st+1,cm-1)
    b = string.sub(str,cm+1,en-1)

    table.insert(t,{})
    table.insert(t[1],1,a)
    table.insert(t[1],2,b)
    
    print(t[1][1],t[1][2])
end

@JeffTheNoob If I understand what you’re trying to do, maybe one of these will help. I took your string, pulled the numbers out of it and created 2 tables. Table t1 contains 1 number per entry. Table t2 contains 2 values per entry as vec2 values.


function setup()
    str = "{200,199},{933,188}"
    t1={}
    t2={}
    c=1
    for w in string.gmatch(str, "%d+") do

        table.insert(t1,w)    -- t1 1 value per entry

        if c==1 then
            a=w
            c=2
        elseif c==2 then
            table.insert(t2,vec2(a,w))   -- t2 2 values per entry         
            c=1
        end
    end
    
    print("\
values in table t1")
    for a,b in pairs(t1) do
        print(a,b)
    end 
    
    print("\
values in table t2")
    for a,b in pairs(t2) do
        print(a,b)
    end                    
end

@Dave1707 Yeah that works great, but if there’s a decimal point it splits it into two values, is there a way around this, if not i can just floor the values and it will work fine.

function setup()
    str = "{200,199},{933,188},{72.9,370}"
    t={}
    c=1
    for w in string.gmatch(str,"%d+") do
        if c==1 then
            a=w
            c=2
        elseif c==2 then
            table.insert(t,{})
            table.insert(t[#t],1,a)
            table.insert(t[#t],2,w)
            c=1
        end
    end
    for i = 1,#t do
        print(t[i][1],t[i][2])
    end
end

How about…

tableStr = "{200, 199}, {933, 188}, {72.9, 370}"
tbl = loadstring("return {" .. tableStr .. "}")()
for k, v in ipairs(tbl) do
    print("Vector " .. k .. ", " .. tostring(v))
    print("X: " .. v[1])
    print("Y: " .. v[2])
    print("End of vector" .. k)
end

loadstring() can do all the hard work for you. Without printing, this is two lines of code.

@JeffTheNoob Try this one. No exactly, but getting closer.

function setup()
    str = "{200,199},{933,188},{72.9,370}"
    t={}
    c=1
    for w in string.gmatch(str,"%d+.%d+") do
        if c==1 then
            a=w
            c=2
        elseif c==2 then
            table.insert(t,{})
            table.insert(t[#t],1,a)
            table.insert(t[#t],2,w)
            c=1
        end
    end
    for i = 1,#t do
        print(t[i][1],t[i][2])
    end
end

@JeffTheNoob I think this one will work


function setup()
    str = "{200,199},{933,188},{72.9,370}"
    t={}
    c=1
    for w in string.gmatch(str,"%d+%.*%d+") do
        if c==1 then
            a=w
            c=2
        elseif c==2 then
            table.insert(t,{})
            table.insert(t[#t],1,a)
            table.insert(t[#t],2,w)
            c=1
        end
    end
    for i = 1,#t do
        print(t[i][1],t[i][2])
    end
end

@dave1707 Did you see mine?

@dave1707 You call loadstring(string). string must be valid Lua, or the function returns nil. It returns a function that, when ran, executes the Lua code. If the code is something like return 0, the function loadstring() returns will itself return 0. That’s how I used it to convert the valid Lua compressed table code into an actual table. I just added "return " before it. Also, as I said that loadstring() returns a function, that is why I have empty parenthesis after th function call, to execute the function retuned.

You can make it work with gmatch if you want, but I think this is more efficient and in fewer lines. As payback for me teaching you something, you can tell me how gmatch works, because I have no idea. :stuck_out_tongue: (Well, Briarfox taught me how to do one thing for the chat room, but still…)

@SkyTheCoder Sorry, but nothing you said above made any sense. I’ll have to keep playing around with it. As for gmatch, that’s a string parser and based on the pattern you use, you can pull just about anything from a string. The only problem is, it’s really complicated trying to set up the pattern, for me anyways. It’s mostly hit and miss right now. It would take a lot of typing if I tried to teach you about it. The easiest is looking in the Lua manual.

@SkyTheCoder - to learn gmatch, maybe have a look at some regex tutorials (gmatch is a cut down version of regex). I learned something about regex last year, and what helped me a lot was when you are trying to understand a pattern, break it into bits and translate them one by one. You’ll find there are relatively few pattern elements that get used a lot, so you can get the hang of it fairly quickly.

@SkyTheCoder I guess I don’t understand how loadstring seperated the string into individual
numbers. At least with gmatch, I can see what I’m trying to do using the pattern. With loadstring, I don’t see what’s doing the work.

@dave1707: loadstring compiles a string into a function. @SkyTheCoder is using it to compile and create a function that returns a table (built from the string of (valid) Lua code he puts together) which he then calls, assigning the result to the variable ‘tbl’. His code is actually more complex than it needs to be due to unnecessarily concatenating his strings. He could have just done:

tbl = loadstring("return { {200, 199}, {933, 188}, {72.9, 370} }")()

It’s a nice trick, and will work, but it is kind of a cheat :wink: Since Codea allows loadstring it’s fine, but not necessarily the best practice in other Lua environments because they may be sandboxed to disallow loadstring. I always prefer another solution if I can find one (like gmatch in this case).

@SkyTheCoder Yes, but I was determined to make it work with gmatch. I don’t recall ever using loadstring, so I’m not sure how it works. I’ll have to look into it because it never hurts to have different ways of doing something. Maybe I can use loadstring for something in the future.

@toadkick I separated the strings and concatenated them to show you could use any compressed table you wanted in it.

I don’t really see myself using any other Lua IDE. If it’s okay in Codea, it’s okay with me. :stuck_out_tongue:

Thanks for the help everyone.@dave1707 the last gmatch pattern seems to ignore values under 10 and the - on negative values. Gmatch patterns look confusing so i went for loadstring. Heres my test project:

function setup()
    parameter.action("Save",function()savetable(e,"eString")savetable(col,"colString")end)
    parameter.action("Clear",function()clearProjectData()end)
    parameter.action("Restart",function()restart()end)

    if readProjectData("eString") ~= nil then
        e = loadstring(readProjectData("eString"))()
    else
        e = {}
    end
    if readProjectData("colString") ~= nil then
        col = loadstring(readProjectData("colString"))()
    else
        col = {}
    end
end

function savetable(tab,key) -- (table to string,key for saved string)
    local s = {"return {"}
    for i=1,#tab do
        s[#s+1] = "{"
        for j=1,#tab[i] do
            s[#s+1] = tab[i][j]
            if j ~= #tab[i] then
                s[#s+1] = ","
            end
        end
        if i ~= #tab then
            s[#s+1] = "},"
        else
            s[#s+1] = "}"
        end
    end
    s[#s+1] = "}"
    tab.str = table.concat(s)
    print(tab.str)
    saveProjectData(key,tab.str)
    s = nil
end

function draw()
    background()
    for i = 1,#e do
        fill(col[i][1],col[i][2],col[i][3],col[i][4])
        ellipse(e[i][1],e[i][2],e[i][3])
    end
end

function touched(touch)
    local c = CurrentTouch
    if c.state == ENDED then
        table.insert(e,#e+1,{c.x})
        table.insert(e[#e],2,c.y)
        table.insert(e[#e],3,math.random(20,200))
        table.insert(col,#col+1,{math.random(0,255)})
        table.insert(col[#col],2,math.random(0,255))
        table.insert(col[#col],3,math.random(0,255))
        table.insert(col[#col],4,math.random(100,230))
    end
end

@JeffTheNoob That’s the trouble with using patterns. You have to know exactly what you’re looking for. Each time I gave you a pattern that worked for the string you gave me, you changed what I was looking for. Since you can use @SkyTheCoder routine, that’s all that matters. Using patterns is very specific and powerful, but you need to know everything your trying to match to create the correct pattern. I’m still learning that. The pattern below works for everything so far, I think.


function setup()
    str = "{200,199},{933,188},{72.9,370},{3.5,-2}"
    t={}
    c=1
    for w in string.gmatch(str,"[+-]*%d*%.*%d+") do
        if c==1 then
            a=w
            c=2
        elseif c==2 then
            table.insert(t,{})
            table.insert(t[#t],1,a)
            table.insert(t[#t],2,w)
            c=1
        end
    end
    for i = 1,#t do
        print(t[i][1],t[i][2])
    end
end