How do I parse a long string with a variable number of arguments?

I have a string that is mostly just a long set of numbers separated by whitespace and newlines.

I want to parse this string out such that I could take each individual number and add it to a table (or tables) as its own item; or assign each individual number its own variable.

Example string to parse:

10 5
65535
0 0 1 2 3 4
5 6 7 8 0 1
2 3 4 5 6 7
8 11 1 2 3 4
5 6 7 8 11 22
0 1 2 3 4 5
6 7 8 11 0 0
1 2 3 4 5 6
7 8

You can’t see it by looking at the string, but this is actually a 10 by 5 heightmap that describes a gentle slope capped by a very sharp spike.

note: heightmaps are not the only reason I want to be able to do this: they just make a good use case for my situation.

Speed is not an issue; this is a plugin I am building to run in Studio. Any solution that can take less then half a second to parse a number is acceptable to my eyes, even if the total run time in the worst case scenarios equals two hours or more.

1 Like

I think you could do table.sort(variable, " ")

Would I assign it like stringtable = table.new(table.sort(longstring, " "))? If so, is there a way to make this sort accept \n newlines as if they are whitespace?

You could probably run string.gmatch on the string:

local numString = -- num string
local numArray = {}
for num in numString:gmatch("%d+") do
	table.insert(numArray, num)
end
6 Likes

Thank you! Marked as solution, for future googlers.

2 Likes

Roblox has a built-in function string.split which can be used to turn this into a 2D array:

local input = [[0 0 1 2 3 4
5 6 7 8 0 1
2 3 4 5 6 7
8 11 1 2 3 4
5 6 7 8 11 22
0 1 2 3 4 5
6 7 8 11 0 0
1 2 3 4 5 6]]

local t = string.split(input, "\n")
for i = 1, #t do
	t[i] = string.split(t[i], " ")
end

turns the input into this table

{{0, 0, 1, 2, 3, 4},
{5, 6, 7, 8, 0, 1},
{2, 3, 4, 5, 6, 7},
{8, 11, 1, 2, 3, 4},
{5, 6, 7, 8, 11, 22},
{0, 1, 2, 3, 4, 5},
{6, 7, 8, 11, 0, 0},
{1, 2, 3, 4, 5, 6}}

This solution calls string.split twice; is it not possible to catch both characters in a single regex, or catch then in a way such that both newlines and whitespace are treated equally, such as the string.gmatch solution slightly further up?

To clarify, my issue is not with how you’ve written the solution, but how hacky it feels.

Thank you for the input and secondary solution though! I will definitely keep that in mind, especially since it may allow me greater control where my limited knowledge of regexes fail.

Essentially, I guess my response is “If I want to add additional separator characters such as commas for a CSV, do I need to add another string.split to the list?”

The string.split function doesn’t accept a string pattern in the second argument, it just treats it as a plain delimiter. If you just want all of the numbers in a single 1D array then gmatch is the right approach. Using string.split to do it would require first replacing the newlines with spaces:
local t = string.split(input:gsub("%s+", " "), " ")
to use any non-number as a delimiter, replace every run of non-numbers with a fixed delimiter:
local t = input:gsub("%D+", " "):split(" ")
or, just use the gmatch solution

All of the numbers in a single 1d array is the approach I’m looking for; each number is a single datapoint which I want to treat separately depending on where in the string it is. Using string.gmatch gives me a recursive for loop in which I can decide which iteration to start treating datapoints differently.

However, your solution is also useful, and if I am parsing your code correctly, guarantees orderliness, which for things like heightmaps is incredibly useful. Thank you!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.