-- Localize functions to avoid table lookups (better performance).
local string_sub, string_find = string.sub, string.find
function string.split_iter(str, delim, include_empty, max_splits, sep_is_pattern)
delim = delim or ","
max_splits = max_splits or -1
local pos, endp, seplen = 1, #str+1, #delim
local plain = not sep_is_pattern
local function iter()
if (not pos) or pos > endp then
return
elseif max_splits == 0 then
local s = string_sub(str, pos)
pos = nil
return s
end
local np, npe = string_find(str, delim, pos, plain)
local s = string_sub(str, pos, np and np - 1)
pos = npe and npe + 1
if include_empty or (s ~= "") then
max_splits = max_splits - 1
return s
else
-- Tail call
return iter()
end
end
return iter
end
--------------------------------------------------------------------------------
function string.split(str, delim, include_empty, max_splits, sep_is_pattern)
local items, n = { }, 0
for part in string.split_iter(str, delim, include_empty, max_splits, sep_is_pattern) do
n = n + 1
items[n] = part
end
return items
end
local function repr(x)
return (type(x) == "string" and ("%q"):format(x)
or tostring(x))
end
local function expect(x, y)
return (rawequal(x, y) or error("assertion failed:"
.." expected "..repr(y)..", got "..repr(x), 2))
end
local function test_string_split()
local items, iter
-- Defaults
items = ("a,b,c"):split()
expect(items[1], "a")
expect(items[2], "b")
expect(items[3], "c")
expect(items[4], nil)
-- Simple split
items = ("a,b,c"):split(",")
expect(items[1], "a")
expect(items[2], "b")
expect(items[3], "c")
expect(items[4], nil)
-- With max_splits
items = ("a,b,c"):split(",", nil, 1)
expect(items[1], "a")
expect(items[2], "b,c")
expect(items[3], nil)
-- With include_empty = true
items = ("a,,b"):split(",", true)
expect(items[1], "a")
expect(items[2], "")
expect(items[3], "b")
expect(items[4], nil)
-- Trailing sep with include_empty = false
items = ("a,b,"):split(",")
expect(items[1], "a")
expect(items[2], "b")
expect(items[3], nil)
-- Trailing sep with include_empty = true
items = ("a,b,"):split(",", true)
expect(items[1], "a")
expect(items[2], "b")
expect(items[3], "")
expect(items[4], nil)
-- With sep_is_pattern = true
items = ("a: \t\n ;b,,,,c"):split("[,;:%s]+", nil, nil, true)
expect(items[1], "a")
expect(items[2], "b")
expect(items[3], "c")
expect(items[4], nil)
-- Iterator
iter = ("a,b,;c"):split_iter("[,;]", true, nil, true)
expect(iter(), "a")
expect(iter(), "b")
expect(iter(), "")
expect(iter(), "c")
expect(iter(), nil)
end
test_string_split()