Jump to content

Module:MultiReplace/sandbox

From Wikipedia, the free encyclopedia
require[[strict]]


	---                                        ---
	---     PRIVATE ENVIRONMENT                ---
	---    ________________________________    ---
	---                                        ---



-- Get the actual arguments
local function get_args (frame, ...)
	return type(frame) ~= 'table' and { frame, ... } or
		type(frame.args) ~= 'table' and frame or
		frame.args[1] and frame.args or
		frame:getParent().args
end


-- Copied from Module:String's `str._escapePattern()`
local function escape_pattern (str)
	return (string.gsub(str, "[%(%)%.%%%+%-%*%?%[%^%$%]]", "%%%0"))
end


	---                                        ---
	---     PUBLIC ENVIRONMENT                 ---
	---    ________________________________    ---
	---                                        ---



local iface = {}


-- Syntax:  #invoke:multiReplace|singlepass|[plain=yes (optional)]|pattern1|
--            replacement1|pattern2|replacement2|...|
iface.singlepass = function (frame, ...)
	local args = get_args(frame, ...)
	local argc, seq, txt, plain =
		0, {}, args[1] or '{{{1}}}', args.plain == 'yes'
	for key, val in ipairs(args) do argc, seq[key] = argc + 1, val end
	if argc % 2 == 0 then
		error('Module:MultiReplace, ‘singlepass’: Unpaired argument: <code>'
			.. argc .. ' = ' .. mw.text.nowiki(seq[argc]) .. '</code>', 0)
	end
	local start, bestStart, bestStop, bestChange
	local len, pos, result, maps, rlen = mw.ustring.len(txt), 1, {}, {}, 0
	for idx = 2, argc, 2 do
		maps[idx - 1], maps[idx] =
			mw.ustring.find(txt, seq[idx], pos, plain)
	end
	while pos <= len do
		bestStart, bestStop, bestChange = len + 1, len, nil
		for idx = 2, argc, 2 do
			start = maps[idx - 1]
			if start and start < pos then
				maps[idx - 1], maps[idx] = mw.ustring.find(txt,
					seq[idx], pos, plain)
				start = maps[idx - 1]
			end
			if start and start < bestStart then
				bestStart, bestStop, bestChange =
					start, maps[idx], idx
			end
		end
		rlen = rlen + 1
		result[rlen] = mw.ustring.sub(txt, pos, bestStart - 1)
		if bestChange then
			maps[bestChange - 1], maps[bestChange] =
				mw.ustring.find(txt, seq[bestChange],
					maps[bestChange] + 1, plain)
			rlen = rlen + 1
			result[rlen] = (plain and seq[bestChange + 1] or
				mw.ustring.gsub(mw.ustring.sub(txt, bestStart,
					bestStop), seq[bestChange],
					seq[bestChange + 1], 1))
		end
		pos = bestStop + 1
	end
	return table.concat(result)
end


-- Syntax:  #invoke:multiReplace|cascade|[plain=yes (optional)]|pattern1|
--            replacement1|pattern2|replacement2|...|
iface.cascade = function (frame, ...)
	local args, argc = get_args(frame, ...), 0
	for _ in ipairs(args) do argc = argc + 1 end
	if argc % 2 == 0 then
		error('Module:MultiReplace, ‘cascade’: Unpaired argument: <code>'
			.. argc .. ' = ' .. mw.text.nowiki(args[argc]) .. '</code>', 0)
	end
	local txt = args[1] or '{{{1}}}'
	if args.plain == 'yes' then
		for idx = 2, argc, 2 do
			txt = mw.ustring.gsub(txt, escape_pattern(args[idx]),
				args[idx + 1])
		end
	else
		for idx = 2, argc, 2 do
			txt = mw.ustring.gsub(txt, args[idx], args[idx + 1])
		end
	end
	return txt
end


-- For compatibility reasons; must not be documented; to delete in the future
iface.main = iface.singlepass


return iface