Converting string to table

I wanted to store a table within a string value and add new values ​​to the list when the player buys an item that isn’t in the table.

I don’t know how to do a check using an if statement since it’s a string.
Screenshot_8
( " } " I’m putting using the script, to insert more values later )

I read about JSONDecode but I couldn’t use it for my problem.

Here is my current script:

script.Parent.MouseButton1Click:Connect(function()
	local player = script.Parent.Parent.Parent.Parent.Parent
	local chars = player:WaitForChild("Data").Characters.Value.."}"
	
	for _,v in pairs(chars) do
		wait()
		if v == "Goku" then
			print("Already has the Character")
		else
			if player:WaitForChild("Data").Coins.Value >= script.Parent.Price.Value then
				player.Data.Coins.Value = player:WaitForChild("Data").Coins.Value - script.Parent.Price.Value
				
				player.Data.Characters.Value = player.Data.Characters.Value..', "Goku"'
				print("Purchased")
			end
		end
	end
end)

Thanks in advance for your attention.

Can you explain why JSONEncode and JSONDecode didn’t work for you? JSON is completely string compatible, so this should work, unless the table contains instances that can’t be encoded.

What does your table contain exactly, and why doesn’t it work with JSON?

If your table does contain a data type that can’t be stringified by JSONEncode, you will most likely have to create a custom encoder to convert to string.

The code you currently have won’t work because even though you technically are showing the table in the string, it is not in table form. It is still but a string, and can’t be read as anything else. This is why you need encoding/decoding like JSON.

--encoding
Table = {"string", "happy", "cow"}
player:WaitForChild("Data").Characters.Value = HTTPService:JSONEncode(Table)

--decoding
Table = HTTPService:JSONDecode(player:WaitForChild("Data").Characters.Value)
1 Like

For Storing that list couldn’t you just make a table and then JSONEncode it and store it in the value? And when you need to insert new values to it, retrieve it, JSONDecode it & it works like a table itself.

1 Like

JSONDecode worked, but the problem is that I didn’t know how to add more characters with that table model

String Value looked like this:

{"Chars":{"Goku":false,"Naruto":true, "Luffy":true}

This is the Old Script

local HttpService = game:GetService("HttpService")

script.Parent.MouseButton1Click:Connect(function()
	local player = script.Parent.Parent.Parent.Parent.Parent
	local jsonData = player:WaitForChild("Data").Characters.Value.."}}"
	local characterStats = HttpService:JSONDecode(jsonData)
	
	if characterStats.Chars.Goku == true then
		print("1")
	else
		if player:WaitForChild("Data").Coins.Value >= script.Parent.Price.Value then
			player.Data.Coins.Value = player:WaitForChild("Data").Coins.Value - script.Parent.Price.Value
			
			--player.Data.Characters.Value = player.Data.Characters.Value..""
		end
	end
end)

Idk how can I change to True the “Goku”

Try decoding the string, editing Goku, and then re-encoding.

The string you showed above looked to still be in JSON form, which means it needs to be decoded.

@colbert2677’s solution is also valid if you aren’t too comfortable with JSON.

1 Like

It’s really the first time that I work with JSON, I have no idea how to do this, do you have any tips?

Okay, so you can use JSON here. Now here’s a difference between lua and other coding contexts. Lua’s only data mechanism is tables, but JSON has both arrays and dictionaries (so does python). Because you’re using the ‘{}’ characters, it wants to assign a string key to some value. What you want is an array which uses ‘[]’.

So something like:

enc_chars = stringValue.Value..']' -- Where stringValue.Value == '["Luffy", "Zoro"'
httpService:DecodeJSON(enc_chars) -- lua table which you can iterate over

p.s. This script will only ever work as a server script unless you make modifications to respect filtering enabled. Not sure if it is or isn’t, but I thought that would be useful pointing out.

1 Like

Thank you so much! This will help me a lot, I’ll try

Alternative suggestion: don’t do this. Instead, make your Characters StringValue a Folder and insert BoolValues (Value is optional) of the characters’ names into said folder. If you need to store them in a DataStore later, you can use a simple function that turns a hierarchy into a table.

local function folderToArray(folder)
    local array = {}

    for _, child in ipairs(folder:GetChildren()) do
        array[#array + 1] = child.Name
    end

    return array
end

folderToArray(Data.Characters)
1 Like

I’ll use your method, it’s the best in case I want to remove or change the name of some character on the list. But, I couldn’t load the saved characters, and I don’t even know if them really saved using the table conversion, I’ll save them all manually for now. Thanks for showing me this method!

Even more alternative suggestion: don’t store the table in a string or values at all.
Instead, store it in a ModuleScript.

Create a new ModuleScript. Then, literally just leave it at default:

local module = {}

return module

To use it, require the module. You will get a table:

local chars = require(player.Characters) -- assuming you named the ModuleScript "Characters" and placed it in the Player

You can insert characters to the table as you would into any table:

table.insert(chars, "Goku")

The part that makes this work is that, any time the ModuleScript is required, it always returns the same table. One script can add a character to the table, and it will have an effect on any other script currently using that table for something. This isn’t specific to ModuleScripts, it’s just how Lua tables are.

The downside to this is that you can’t easily see what’s going on with the Explorer, like you can with your current method or colbert’s, and saving the place to a file (for whatever reason) does not keep the contents of the ModuleScript.

1 Like

Also, something that’s easy to miss:

local chars = player:WaitForChild("Data").Characters.Value.."}"

Here is what chars will turn into:

local chars = '{"Naruto","Luffy","Goku"}'

If you try to do a pairs loop on it, it will fail, because it is a string, not a table.

local table = { "Naruto","Luffy","Goku" }
local string = '{"Naruto","Luffy","Goku"}'

for _,v in pairs(table) do print(v) end -- succeeds
for _,v in pairs(string) do print(v) end --  for _,v in pairs(string) do print(v) end:1: bad argument #1 (table expected, got string)

You can use your original method just fine, you just were really confused by all the options.
Instead of putting in e.g. {"Naruto","Luffy","Goku" in the StringValue, put Naruto,Luffy,Goku (without any quotes or such).
This makes it much easier to work with them, as such:

local list = "Naruto,Luffy,Goku"

function csvToTable(list) -- Comma-Separated-Values to Table
	local out = {}
	for entry in string.gmatch(list, "[^,]+") do -- [^,] means: anything that is not a comma (the ^ is the not). + means: as many of it in a row as you can get
		table.insert(out, entry)
	end
	return out
end

function tableToCsv(list)
	return table.concat(list, ",") -- turn the table into one string, with a comma between each value
end

-- test the function
for _,v in pairs(csvToTable(list)) do print(v) end

-- add a character to the table
list = list .. ",Lum" -- the comma is necessary to separate the characters

-- test the function
for _,v in pairs(csvToTable(list)) do print(v) end

-- add a character to the table
local tab = csvToTable(list)
table.insert(tab, "Astroboy")

-- test tableToCsv
print(tableToCsv(tab)) -- Naruto,Luffy,Goku,Lum,Astroboy
5 Likes

I’ll try this later too, I’ve never worked with modules before, it’s something I’m still avoiding because it looks more complicated than the common scripts, I probably wouldn’t know how to save it to the DataStore, but about adding the character, I needed to that the person bought the character to use it, using a module would not unlock the character for everyone on the server?

1 Like

At that moment I thought it had a function like “tostring()”, I wanted to find some way to convert the string

But as I said to Colbert, maybe using values in a folder is better for deleting them later

I’ve made a massive edit to my last post that should’ve just been its own post

but about adding the character, I needed to that the person bought the character to use it, using a module would not unlock the character for everyone on the server?

If you keep a separate ModuleScript for each player, it wouldn’t. Each of them will give a different table, but if you require the same one multiple times, it will always produce its own table.

At that moment I thought it had a function like “tostring()”, I wanted to find some way to convert the string

table.concat(chars, ",") will turn a table into a string, with a comma (and nothing else) between each value. It’s a native Lua function, so you will find a lot of information about it online. Unlike JSONEncode/JSONDecode, however, it will not save dictionaries (e.g. {foo = "bar", [workspace] = 15}), so it has limited use (and your use is within that limit)

1 Like

this method you sent is interesting, I was still preparing the other one, but this one seems to be easier to add new characters (if it doesn’t take a lot of work to save), my data script was getting really messy.

Edit: I understand now how to save that, I’ll try here.

I probably won’t use this last part for now, so it will serve well, thank you!

The main point of not using a ModuleScript for me is so that you have the benefit of replicated and shared data.

ModuleScripts return different instances when required by the client or the server, meaning that you’d have to use a remote every time you want to read or write data rather than being able to do both quickly and comfortably from both environments. ModuleScripts would be my default in any other case though, but not for data that the client may also be using - at least not without an equal method of replicating the data it gets.

Replication can be done manually though by just having the server fire the table to the client and letting the client update its own copy of the ModuleScript, but remotes don’t pass by reference for values that can’t be serialised, they make a copy of the data and transfer that over the network.

Quick thing on your other other post as well: could you not substitute the csvToTable string using string.split since you’re expecting all values to be separated by values? It will return an array, in order, of the list you made. I think the gmatch and this accomplish the same thing, but split works in plain text while gmatch allows you to use string patterns.

local function csvToTable(list)
    return string.split(list, ",")
end
5 Likes

ig this looks better… i dont really know just change it to json and by http u can make it real table:

	local list = '{["age"] = 21;["Name"] = "jonh"}'

	list = list:gsub("%[", ""):gsub("%]", "")

	list = list:gsub(";", ",")

	list = list:gsub("=", ":")

	list = list:gsub("'", '"')

	local json = game.HttpService:JSONDecode(list)
	print(json)
	return json

im so late but nvm if some one got same error or want this code (: