User:Gerbrant/edit/multiReplace.js

Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
try
{
	"A".replace(/A|(B)/, function(a, b)
	{
		if(b != undefined) throw false;
		return a;
	});
}
catch(e)
{
	(function(m)
	{
		alert(m);
		throw new Error(m);
	})("The script Gerbrant.edit.multiReplace cannot be used because your browser's implementation of String.prototype.replace is buggy. More specifically, it doesn't handle non-participating capturing groups correctly.");
}

module("Gerbrant.edit.multiReplace", function()
{

patterns = [];
handlers = [];
indices = [];
var j = 1;

this.add = function(p, h)
{
	var n = p.match(/\((?!\?)/g);
	if(n) n = n.length + j;
	else n = j;
	patterns.push(p.replace(/\\(\d+)/, function(a, b)
	{
		return "\\" + (+b + n - 1);
	}));
	handlers.push(h);
	indices.push([j, ++n]);
	j = n;
}

//equivalent aan a.slice(b, e), maar dat werkt niet voor arguments
function sliceArg(a, b, e)
{
	n = [];
	while(b < e) n.push(a[b++]);
	return n;
}

this.handler = function(a)
{
	var i, idx;
	for(i in indices)
	{
		idx = indices[i];
		if(arguments[idx[0]] != undefined)
			try
			{
				return handlers[i].apply(a, sliceArg(arguments, idx[0], idx[1]));
			}
			catch(e)
			{
				alert(e.message + "\n\n" + handlers[i]);
				return a;
			}
	}
	throw "Failed sanity check.";
}

this.getRE = function()
{
	return new RegExp("(" + patterns.join(")|(") + ")", "g")
};

this.replace = function(t)
{
	return t.replace(this.getRE(), this.handler);
};

});