Improve the implementation of parenthetical_split()...

...and make it local to wml_actions.remove_unit_overlay().
This commit is contained in:
J. Tyne 2013-01-25 22:10:57 +00:00
parent 462afa50b4
commit 70351c6209
2 changed files with 40 additions and 52 deletions

View file

@ -391,53 +391,4 @@ function helper.shuffle( t )
end
end
--! Returns an iterator over the pieces of str that are deliminated by separator,
--! with the provision that anything enclosed in parentheses is not split.
--! If nil, separator defaults to ",", open_paren to "(" and close_paren to ")".
--! This is generally less capable than parenthetical_split() in
--! serialization/string_utils.cpp, although this function can handle separators
--! and parentheses that consist of more than one character.
function helper.parenthetical_split(str, separator, open_paren, close_paren)
local sep = separator or ","
local p1 = open_paren or "("
local p2 = close_paren or ")"
-- Cache the string length.
local str_len = str:len()
-- Cache the offsets (length - 1).
local sep_off = sep:len() - 1
local p1_off = p1:len() - 1
local p2_off = p2:len() - 1
-- Tracks our progress through the string.
local i = 1
return function()
-- Test for end of string.
if i > str_len then return nil end
local start = i
local p_count = 0
-- while not end-of-string and (in parens or not at a separator)
while i <= str_len and (p_count ~= 0 or str:sub(i, i+sep_off) ~= sep) do
-- Check for parentheses
if str:sub(i, i+p1_off) == p1 then
p_count = p_count + 1
i = i + p1_off + 1
elseif str:sub(i, i+p2_off) == p2 then
p_count = p_count - 1
i = i + p2_off + 1
else
i = i + 1
end
end
-- Skip the separator.
local stop = i - 1
i = i + sep_off + 1
return str:sub(start, stop)
end
end
return helper

View file

@ -389,12 +389,49 @@ end
function wml_actions.remove_unit_overlay(cfg)
local img = cfg.image or helper.wml_error( "[remove_unit_overlay] missing required image= attribute" )
-- Splits the string argument on commas, excepting those commas that occur
-- within paired parentheses. The result is returned as a (non-empty) table.
-- (The table might have a single entry that is an empty string, though.)
-- Spaces around splitting commas are stripped (as in the C++ version).
-- Empty strings are not removed (unlike the C++ version).
local function parenthetical_split(str)
local t = {""}
-- To simplify some logic, end the string with paired parentheses.
local formatted = (str or "") .. ",()"
-- Isolate paired parentheses.
for prefix,paren in string.gmatch(formatted, "(.-)(%b())") do
-- Separate on commas
for comma,text in string.gmatch(prefix, "(,?)([^,]*)") do
if comma == "" then
-- We are continuing the last string found.
t[#t] = t[#t] .. text
else
-- We are starting the next string.
-- (Now that we know the last string is complete,
-- strip leading and trailing spaces from it.)
t[#t] = string.match(t[#t], "^%s*(.-)%s*$")
table.insert(t, text)
end
end
-- Add the parenthetical part to the last string found.
t[#t] = t[#t] .. paren
end
-- Remove the empty parentheses we had added to the end.
table.remove(t)
return t
end
-- Loop through all matching units.
for i,u in ipairs(wesnoth.get_units(cfg)) do
local ucfg = u.__cfg
local t = {}
for w in helper.parenthetical_split(ucfg.overlays) do
if w ~= img then table.insert(t, w) end
local t = parenthetical_split(ucfg.overlays)
-- Remove the specified image from the overlays.
for i = #t,1,-1 do
if t[i] == img then table.remove(t, i) end
end
-- Reassemble the list of remaining overlays.
ucfg.overlays = table.concat(t, ',')
wesnoth.put_unit(ucfg)
end