How to serialize what player has written

I want to add signs into my game and allow a player to input text across 4 lines. However, I am unsure how to effectively save what they have written using a string

self.Coords[x][y][z] = BlockId .. '"Test_More_Lines_Ok"'

-- later on
local NewLine1 = string.find(extraData.String, "_")
local NewLine2 = string.find(string.sub(extraData.String, NewLine1 + 1), "_")
local NewLine3 = string.find(string.sub(extraData.String, NewLine2 + 1), "_")
print("String", NewLine1, NewLine2, NewLine3)
local Line1 = string.sub(extraData.String, 2, NewLine1 - 1)
local Line2 = string.sub(extraData.String, NewLine1 + 1, NewLine2 - 1)
local Line3 = string.sub(extraData.String, NewLine2 + 1, NewLine2 - 1)
local Line4 = string.sub(extraData.String, NewLine3 + 1, NewLine3 - 2)
print(Line1, Line2, Line3, Line4)
NewBlock.PrimaryPart.Sign.SignData["Line1"].Text = Line1
NewBlock.PrimaryPart.Sign.SignData["Line2"].Text = Line2
NewBlock.PrimaryPart.Sign.SignData["Line3"].Text = Line3
NewBlock.PrimaryPart.Sign.SignData["Line4"].Text = Line4

Problem is, what if a player has an underscore as part of their text?? What do I do then? How can I filter this out?

Ideally, I need a way to split the string into ‘4’ segments to represent each line. However, a player might not have anything on a specific line, for example, if they just have text on line 4, it’d look like

self.Coords[x][y][z] = BlockId .. '"___Ok"'

Which just looks bad. SO are there are better solutions??

PLEASE NOTE, I CANNOT SAVE IT AS A TABLE OR ANYTHING LIKE THAT! IT MUST BE SAVED UNDER A STRING! DO NOT SUGGEST ANY OTHER ALTERNATIVE

This is unfortunately not possible without a table. Datastore cannot save string values. You HAVE to use alternatives.

I don’t HAVE to use alternatives. This is currently being saved as is, so what I am doing IS working

My question does not relate to saving. I’m asking how to format my data in this string format, which I know there is a way to do, and using something like string.match would make it possible

You don’t need complex stuff for this,
Just connect the strings together and later when loading split them with string.split .
For example:

Datatobesaved = data1…"|"…data2…"|"…data3

Data:
data1|data2|data3

Loading it:

string.split(datasaved,"|")

And done

Just make sure the data never has the split string, or it will break.

What I mean:
NEVER DO
“Cooldata|”|…etc

maybe do \n it does a new line for you

it can

I don’t have a very big brain idea, brain bigger than Albert Einstein, but it’s definitely an idea for this approach:

But you could censor the line in the sign that have the split content before saving it, for instance if you want to split using \n, censor the word \n on the sign. This is the only way I can think of.

Huh. You don’t need to worry about that since if you split it and it returns blank or nil (I don’t know) it will be a blank line. You don’t need to care about how it looks like tho. \n\n\n exists in lua too, right?

Alright so this is my answer: Censor the word \n (because it’s not a common word to put in a sign and underscores is common on putting on Roblox players usernames which censoring underscore isn’t a very good idea) in the sign’s content before saving and then split it to a table and boom.

This alternative answer was supposed to not to tell but I have to, because you do not need to censor anything in the sign, but the split content’s length will be over than the maximum length of the sign. And later splitting it will avoid all the problems you said

Alright bye I have to sleep now :wave:

Covert a table with the data to a string using JSONEncode then save it to data store. Then use JSONDecode to get it back to a table when ur loading it

1 Like

If you’re adamant about not using tables, how about splitting the string at underscores and filtering out any entries of the resulting table that contain no data; e.g.

local function filter<T>(array: {T}, predicate: (T, number) -> boolean): {T}
  local new = {}

  for index, entry in ipairs(array) do
    if predicate(entry, index) == true then
      table.insert(new, entry)
    end
  end

  return new
end

local rawValue = string.split(data, "_")

local values: {string} = filter(rawValue, function(value)
  return value and #value > 0
end)

local line1 = values[1] or ""
local line2 = values[2] or ""
local line3 = values[3] or ""
local line4 = values[4] or ""

Why not use a newline character?

local line1 = "This is some text"
local line2 = "That spans four lines"
local line3 = "Like a Minecraft sign"
local line4 = "Yadda yadda yadda"

-- Serialize by joining with "\n"
local serialized = line1 .. "\n" .. line2 .. "\n" .. line3 .. "\n" .. line4

-- Deserialize by splitting on "\n", unpacking the table into your 4 variables
local line1, line2, line3, line4 = table.unpack(serialized:split("\n"))

I guess my answer is don’t use a common character like an underscore, but rather one that wouldn’t be valid in the first place - assuming that newline characters aren’t allowed, since you’re splitting into 4 lines anyway.

1 Like

Addendum to this. Instead of having line1, line2, line3 etc, you really ought to be using tables and then your serialization strategy (join/split, use JSON, etc) can be independent of this.

local lines = {
"There once was a man from Peru",
"Who dreamed he was eating his shoe",
"He woke with a fight in the middle of the night",
"And found his dream had come true"
}

local serialized = table.join(lines, "\n")
local deserialized = serialized:split("\n")
1 Like

What’s to prevent a player from just typing \n tho? To my knowledge, typing it in a textbox does nothing. So a player could break this by just doing \n \n \n \n \n \n over and over again

image

The backslash is an escape character that only works in Lua string literals, not a TextBox. So, they’d be typing "\\n" (double backslash resolves to a single backslash) and not "\n".

Also, for what it’s worth - you could just let them type any old string and then count the number of newlines in it.

-- You can use string.gsub to count pattern occurrences:
local _, lineCount = str:gsub("[\n\r]") -- \n and \r are both newlines
-- Add one to the line count, because "foo" is 1 line with no \n, and "foo\nbar" is 2 with one \n
lineCount += 1