For anyone interested, I created a function that allows strings to be split with a delimiter of any character and any number of characters. I am very open if anyone would like to improve my code in any way.
local explode = function(str, delimiter)
local result = {};
local startPoint, endPoint = 1, 1;
for i = 1, str:len() do
if (i + 1) > str:len() then
endPoint = str:len();
end
if (str:sub(i, i + (delimiter:len() - 1)) == delimiter) then
endPoint = i - 1;
table.insert(result, str:sub(startPoint, endPoint));
startPoint = i + (delimiter:len());
elseif (i == str:len()) then
endPoint = str:len();
table.insert(result, str:sub(startPoint, endPoint));
end
end
return result;
end
Example
local foods = "apple$%$%orange$%$%tomato$%$%pizza";
local foodTable = explode(foods, "$%$%");
for i, food in pairs(foodTable) do
print(food);
end
local function explode(str, delimiter)
local fragments = {}
local previousPosition = 1
for pos in string.gmatch(str, "()(" .. string.gsub(delimiter, "%%", "%%%%") ..")") do
table.insert(fragments, string.sub(str, previousPosition, pos - 1))
previousPosition = pos + string.len(delimiter)
end
table.insert(fragments, string.sub(str, previousPosition, string.len(str)))
return fragments
end
print(table.concat(explode("apple$%$%orange$%$%tomato$%$%pizza", "$%$%"), "\n"))
Why does nobody use string.find? It has this nice parameter to ignore string patterns:
local function explode(str,delimiter)
local res,i = {},1
while i <= #str do
local a,b = str:find(delimiter,i,true)
if not a then break end
table.insert(res,str:sub(i,a-1))
i = b + 1
end
table.insert(res,str:sub(i))
return res
end
for k,v in pairs(explode("Dis:.:is:.:weird",":.:")) do
print(k..".",v)
end
--> 1. Dis
--> 2. is
--> 3. weird
Exploding ":.:Dis:.:is:.:weird:.:" would result in {"","Dis","is","weird",""}, which is fine?
local tab = {"hello m8!!","there are 2 many","Worlds"}
local divider="BBB"
local divlen = string.len(divider)
function TableToString(t)
local str = ""
for i = 1,#t do
str = str .. t[i] .. divider
end
return str
end
function StringToTable(s)
local t = {}
for k in string.gmatch(s, ".-"..divider) do
t[#t+1]=string.sub(k,0,string.len(k)-divlen)
end
return t
end
local str = TableToString(tab)
print(str)
-->hello m8!!BBBthere are 2 manyBBBWorldsBBB
local t = StringToTable(str)
for k,v in pairs(t) do
print(k..".",v)
end
-->1. hello m8!!
-->2. there are 2 many
-->3. Worlds
This might be the fastest solution? Not sure about that but with this way, it’s pretty easy.
Or if you’re lazy and want an actual function parameter for using regex and capping results:
local function explode(str, delim, useRegex, maxResults) -- useRegex defaults to false, maxResults defaults to infinite
local results = {}
maxResults = maxResults or -1
if #str > 0 and maxResults ~= 0 then
local num, start = 1, 1
local i1, i2 = str:find(delim, start, not useRegex)
while i1 and maxResults ~= 1 do
results[num] = str:sub(start, i1-1)
num = num+1
start = i2+1
i1, i2 = str:find(delim, start, not useRegex)
maxResults = maxResults-1
end
results[num] = str:sub(start)
end
return results
end
for i, v in pairs(explode("-Dis:.:works:.:fine//", ":.:")) do
print(i .. ".", v)
end
--> 1. -Dis
--> 2. works
--> 3. fine//
for i, v in pairs(explode("-Dis:.:works:.:fine//", ":.:", false, 2)) do
print(i .. ".", v)
end
--> 1. -Dis
--> 2. works:.:fine//
for i, v in pairs(explode("-Dis:.:works:.:fine//", "%w+", true)) do
print(i .. ".", v)
end
--> 1. -
--> 2. :.:
--> 3. :.:
--> 4. //
I had this hidden away in some script I wrote a year ago. Might be helpful? Not sure if I wrote this or got it online somewhere.
local function SplitString(str, sep)
local fields = {}
local pattern = string.format("([^%s]+)", sep)
str:gsub(pattern, function(c) fields[#fields + 1] = c end)
return fields
end
sep is the delimiter. Example use:
local str = "Test,ABC,123,XYZ"
local items = SplitString(str, ",")
for _,item in pairs(items) do print(item) end