In my nodejs(javascript) program, users are able to enter text and have it changed with a regular expression that they have inputted. I would also like the user to be able to enter text to be capitalized or lower-cased. If the user inputs the string "StackOverflow is great!", the regular expression (.), and sets it to be replaced by uppercase($1), the program should return "STACKOVERFLOW IS GREAT!" I can do this with:
var text = "StackOverflow is great!";
var regexp = new RegExp("(.)", "g");
var replaceWith = "uppercase($1)";
var uppercaseMatch = /uppercase\(([^)]+)\)/g.test(replaceWith);
var lowercaseMatch = /lowercase\(([^)]+)\)/g.test(replaceWith);
var result = text.replace(regexp, function() {
var argsCount = arguments.length;
if(uppercaseMatch) {
if(argsCount === 5) {
return arguments[1].toUpperCase() + arguments[2];
} else if (argsCount === 4) {
return arguments[1].toUpperCase();
}
} else if (lowercaseMatch) {
if(argsCount === 5) {
return arguments[1].tolowerCase() + arguments[2];
} else if (argsCount === 4) {
return arguments[1].tolowerCase();
}
} else {
if(argsCount === 5) {
return arguments[1] + arguments[2];
} else if (argsCount === 4) {
return arguments[1];
} else if (argsCount === 3) {
return replaceWith;
}
}
});
console.log(result);
It also works if they lowercase the string, and then it will return "stackoverflow is great!" This code will also run correctly if they do not enter any text to be uppercase or lowercase, such as [oO]
as the regex and 0
as the replaceWith. However, it will not work with \b(\w)
as the regex, and uppercase($1)
as the replaceWith. I would also like this to work if a user wants to use multiple backreferences in replaceWith, such as a replace of ([aeiou])
and replaceWith $1$1
. It should also be able to have more than one backreference, such as replacing ([a-zA-Z])([a-zA-Z]?)
with uppercase($1)$2
. Finally, I would like it to work when a user has both uppercase and lowercase in the replaceWith, like this: replace ([a-zA-Z']+,*)([.,?!\s]|)([a-zA-Z']+|)
with uppercase($1)$2lowercase($3)
.
I can suggest something like this:
function fnReplace(regex, from, to) {
return from.replace(regex, function() {
var args = [].slice.call(arguments, 0);
return to.replace(/(\w+)\(\$(\d+)\)|\$(\d+)/g, function(_, fn, a1, a2) {
return fn ? args[a1][fn]() : args[a2];
});
});
}
Example:
s = fnReplace(
/(\w+) (\w+)/,
'hello THERE',
'toUpperCase($1) + toLowerCase($2) + $2 $1');
console.log(s) // HELLO + there + THERE hello
It allows arbitrary string functions in replacement:
s = fnReplace(
/(\w+) (\w+)/,
'hello THERE',
'bold($1) + sup($2)');
// <b>hello</b> + <sup>THERE</sup>
If this is not desired, change the inner regex to be like:
return to.replace(/(toUpperCase|toLowerCase|...)\(\$(\d+)\)|\$(\d+)/g, function(_, fn, a1, a2) {
return fn ? args[a1][fn]() : args[a2];
});