Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
3

Decoding a string into a table with multiple data types?

Asked by 9 years ago

Okay so, I'm trying to take an input and decode it into a table of numbers and strings an example of an input is

"Weapon:Starter Sword:A basic starter sword:none:ohls:5:45:100:0"

The code to decode and encode is:

local m = {}
local player = game.Players.LocalPlayer

function m.Decode(string)
    local inventory = {}
    local currentposition = 1
    local currentstring = ""
    for i = 1, string.len(string) do
        if not string.sub(string, i) == ":" then
            currentstring = currentstring..string.sub(string, i, i + 1)
        else
            table.insert(inventory, currentposition, currentstring)
            currentstring = ""
            currentposition = currentposition + 1
        end
    end
    return inventory
end

function m.Encode(table) --takes the string that was decoded from the table above^
    local string = ""
    for i = 1, #table do
        if i == #table then
            string = string..table[i]
        else
            string = string..table[i]..':'
        end
    end
    return string
end
--Weapon:Starter~Sword:A~basic~starter~sword:none:ohls:5:45:100:0
return m

It takes all the strings between the ':'s and adds them to a table. I also need it to check if the number in a string is a number and make it a number value instead of a string value.

2 answers

Log in to vote
5
Answered by
Goulstem 8144 Badge of Merit Moderation Voter Administrator Community Moderator
9 years ago

Looks like you need to really get to know the string.gmatch function(:



string.gmatch Info

The string.gmatch function actually returns an iterator function.. and each time said function is called then it will return any string in the first argument(the string you're 'gmatching') that matches the pattern in the second argument(the pattern you want to 'gmatch').


So, because this returns an iterator function.. can you think of any loops that take in iterator functions? The generic for loop! The syntax for the generic for loop is;

for [values] in [iterator function] do


Since the string.gmatch function only returns 1 value(the matching string) then you only need 1 variable in the '[values]' spot. This variable will hold whatever potential string match, from within the given string, that would match the given pattern.


So I keep talking about 'given string' and 'given pattern' right? What the heck am I talking about?

The string.gmatch function takes in 2 arguments!

  • 1 ~ The string to match

  • 2 ~ The pattern to match the string



String Patterns

When I say "The pattern to match the string" then what i'm meaning is that there are literally syntax patterns to match strings with. There are various patterns.. %d gets numbers.. %a gets letters.. %u gets uppercase letters.. etc..


So String Patterns are literally used for defining patterns that you want to search for in a string. Just an example before we continue - if I wanted to get the letter 'G', then any lowercase letters after that, then i'd use the pattern 'G%l+'. And an example of full usage;

--Pretty redundant statement.. this is just an example(;
--This is the string you're going to match
local str = 'Goulstem is so Cool, Goul is God'
--This is the pattern you'll be matching with
local pattern = 'G%l+'

--Use the generic for loop, with string.gmatch iterator function.
for i in string.gmatch(str,pattern) do
    print(i)
end

--[[Output]]--

 --Goulstem
 --Goul
-- God

As you can see, the code printed the three texts.. because those three string of characters matched the given pattern!



Main Answer

So, now that i've sort of walked you through basic understanding of the string.gmatch function and how string patterns operate.. then I think you're ready for the main lesson.

You need to use :%w+ as a pattern.. to find any alphanumeric in the string(uppercase, lowercase, or diget) after a colon. This way, you can capture everything in between the colons. But there's some more to it.. with this pattern then it also captures the colon! So you have to use the string.sub function to seclude the colon from the string capture(:

Once you get the string returned from this pattern then you need to check if it's a number, or a bool.. if it's either or then you need to insert it into a separate table as said datatype.. otherwise keep it a string.



Code

local m = {}

m.Decode = function(str)
    --Predefine table
    local tab = {}
    --Predefine string pattern
    local pattern = ':%w+'
    --Generic for loop to iterate through string
    for i in string.gmatch(str,pattern) do
        --Limit capture
        i = i:sub(2)
        --Check if it's a bool
        if i == 'true' then
            table.insert(tab,true)
        elseif i == 'false' then
            table.insert(tab,false)
        --Check if it's a number
        elseif tonumber(i) ~= nil then
            table.insert(tab,tonumber(i))
        --Otherwise, keep it a string
        else
            table.insert(tab,i)
        end
    end
    --Return decrypted table
    return tab
end

--Your Encrypt function was fine.

--[[

Usage:

local str = ':Hi:2:true:Lol'
local tab = m.Decode(str)

for i,v in pairs(tab) do
    print(v)
end

--> Hi
--> 2
--> true
--> Lol

]]--
0
Format question: How you you make lines and large text? yumtaste 476 — 9y
0
Lines: hyphens across the whole pad. Large Text: Text, next line 5 hyphens. Goulstem 8144 — 9y
Ad
Log in to vote
1
Answered by 9 years ago

You could use the tonumber() function to check if the current string made into a number doesn't equal nil and then add that number (from using tonumber()) to the table if it doesn't equal nil. Otherwise, just add the string in normally.

For example, if you had "50" and used the tonumber() function on it, it would return 50 as a number, as opposed to using the tonumber() function on "Sword", which would return nil since sword is not a number.

So, for your decoding function, you can do this:

function m.Decode(string)
    local inventory = {}
    local currentposition = 1
    local currentstring = ""
    for i = 1, string.len(string) do
        if not string.sub(string, i) == ":" then
            currentstring = currentstring..string.sub(string, i, i + 1)
        else
            if tonumber(currentstring) ~= nil then --Checks if the string converted to a number returns an actual number.
                table.insert(inventory, currentposition, tonumber(currentstring)) --Adds the string converted to a number into the table, it would just add in the string if you didn't do this, which is not what you want.
            else
                table.insert(inventory, currentposition, currentstring)
            end
            currentstring = ""
            currentposition = currentposition + 1
        end
    end
    return inventory
end

You don't need to do anything for the encoding function though as numbers are automatically made into strings when they is used in string concatenation.

I hope this helped you. If it did, be sure to accept it.

Answer this question