Series = class(Turbine.Object);
function Series:Constructor(str)
-- Eliminate unneeded chars
str = string.gsub(str, "([0-9]) +([0-9])", "%1;%2"); -- accept space-delimited numbers
str = string.gsub(str, "[^0-9,;.-]", ""); -- remove garbage chars
str = string.gsub(str, "^[^0-9]+", ""); -- remove leading nonnumeric chars
str = string.gsub(str, "[^0-9]$", ""); -- remove trailing nonnumeric chars
str = string.gsub(str, "%.+", "-"); -- replace "..." with "-"
str = string.gsub(str, ",", ";"); -- replace "," with ";"
str = string.gsub(str, "[^0-9][^0-9]+", ";"); -- eliminate unterminated ranges
self.str = str;
self.caret = 1;
self.prev = nil;
end
-- For-loop expression for getting the numbers in order (with optional "safety" limit value)
function Series:numbers(safety)
self.safety = safety;
self.iterator = function(state, num)
local last = state[4];
if (last) then
-- Continue current interval
if (num < last) then
return num + 1;
elseif (num > last) then
return num - 1;
end
end
-- End of interval; get the next semicolon-delimited element from self.str
local f, s, var = unpack(state);
var = f(s, var);
if (var == nil) then
return nil;
end
-- Get the next range and apply "safety" limit (if any)
local first = tonumber(string.match(var, "^[0-9]+"));
last = tonumber(string.match(var, "[0-9]+$"));
if (self.safety) then
first = math.min(first, self.safety);
last = math.min(last, self.safety);
end
-- Save end of range; return first number in range
state[4] = last;
return first;
end
-- Iterate over semicolon-delimited elements in self.str
return self.iterator, { string.gmatch(self.str, "[^;]+") };
end
function Series:tostring()
local str = string.gsub(self.str, "-", "..."); -- replace "..." with "-"
return str;
end
Thurallor = Thurallor or {};
Thurallor.Utils = Thurallor.Utils or {};
Thurallor.Utils.Series = Series;