使用字符串变量动态创建 RegExp

IT技术 javascript regex
2021-01-26 15:13:03

假设我想让以下内容可重用:

function replace_foo(target, replacement) {
   return target.replace("string_to_replace",replacement);
}

我可能会做这样的事情:

function replace_foo(target, string_to_replace, replacement) {
   return target.replace(string_to_replace,replacement);
}

使用字符串文字,这很容易。但是如果我想对正则表达式更加棘手怎么办?例如,假设我想替换 string_to_replace. 本能地,我会尝试通过执行以下操作来扩展上述内容:

function replace_foo(target, string_to_replace, replacement) {
   return target.replace(/^string_to_replace/,replacement);
}

这似乎不起作用。我的猜测是它认为string_to_replace是字符串文字,而不是表示字符串的变量。是否可以使用字符串变量动态创建 JavaScript 正则表达式?如果可能的话,这样的事情会很棒:

function replace_foo(target, string_to_replace, replacement) {
   var regex = "/^" + string_to_replace + "/";
   return target.replace(regex,replacement);
}
6个回答

还有new RegExp(string, flags)哪里flagsgi所以

'GODzilla'.replace( new RegExp('god', 'i'), '' )

评估为

zilla
/使用这种形式时也省略正则表达式分隔符。
2021-04-06 15:13:03

使用字符串文字,这很容易。

并不真地!该示例仅替换第一次出现的string_to_replace更常见的是,您想要替换所有出现的内容,在这种情况下,您必须将字符串转换为全局 ( /.../g) RegExp。您可以使用new RegExp构造函数从字符串中执行此操作

new RegExp(string_to_replace, 'g')

这样做的问题是字符串文字中的任何正则表达式特殊字符将以它们的特殊方式表现,而不是普通字符。你必须反斜杠转义它们才能解决这个问题。不幸的是,没有内置函数可以为您执行此操作,因此您可以使用以下函数:

function escapeRegExp(s) {
    return s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
}

另请注意,当您在 中使用 RegExp 时replace(),替换字符串现在也有一个特殊字符$如果您想$在替换文本中包含文字也必须对此进行转义

function escapeSubstitute(s) {
    return s.replace(/\$/g, '$$$$');
}

(四个$s 因为它本身就是一个替换字符串——啊!)

现在您可以使用 RegExp 实现全局字符串替换:

function replace_foo(target, string_to_replace, replacement) {
    var relit= escapeRegExp(string_to_replace);
    var sub= escapeSubstitute(replacement);
    var re= new RegExp(relit, 'g');
    return target.replace(re, sub);
}

多么痛苦。幸运的是,如果您想要做的只是一个直字符串替换而没有正则表达式的附加部分,那么有一个更快的方法:

s.split(string_to_replace).join(replacement)

...就这样。这是一个普遍理解的习语。

说我想替换除 string_to_replace 之外的所有内容

这是什么意思,您想替换所有不参与与字符串匹配的文本?替换^当然不是这个,因为^意味着字符串开始标记,而不是否定。^只是[]字符组中的否定也有负面的前瞻(?!...),但在 JScript 中存在问题,因此您通常应该避免它。

您可以尝试匹配字符串的“所有内容”,并使用函数丢弃匹配字符串之间的任何空段:

var re= new RegExp('(.*)($|'+escapeRegExp(string_to_find)+')')
return target.replace(re, function(match) {
    return match[1]===''? match[2] : replacement+match[2];
});

在这里,再次拆分可能更简单:

var parts= target.split(string_to_match);
for (var i= parts.length; i-->0;)
    if (parts[i]!=='')
        parts[i]= replacement;
return parts.join(string_to_match);

正如其他人所说,使用new RegExp(pattern, flags)这样做。值得注意的是,您将向此构造函数传递字符串文字,因此必须对每个反斜杠进行转义。例如,如果您希望正则表达式匹配反斜杠,则需要说new RegExp('\\\\'),而正则表达式文字只需要是/\\/. 根据您打算如何使用它,您应该警惕将用户输入传递给这样的函数而没有足够的预处理(转义特殊字符等)。否则,您的用户可能会得到一些非常意想不到的结果。

这个答案虽然不是最详细的,但确实提到了一个我刚刚坚持了一个小时关键细节:逃避任何特殊序列。例如,我正在搜索以某个术语开头的单词,因此我需要的正则表达式是/\b[term]\B/,但是在构建它时我需要调用new RegExp("\\b"+ term + "\\B"). 小而重要的区别,很难发现,因为直接将其用作正则表达式确实可以按预期工作。
2021-03-17 15:13:03

是的你可以。

https://developer.mozilla.org/en/JavaScript/Guide/Regular_Expressions

function replace_foo(target, string_to_replace, replacement) {
   var regex = new RegExp("^" + string_to_replace);
   return target.replace(regex, replacement);
}

我想我有一个很好的例子来突出显示字符串中的文本(它发现不是在看寄存器而是使用寄存器突出显示)

function getHighlightedText(basicString, filterString) {

    if ((basicString === "") || (basicString === null) || (filterString === "") || (filterString === null)) return basicString;

    return basicString.replace(new RegExp(filterString.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\\\$&'), 'gi'),
        function(match)
            {return "<mark>"+match+"</mark>"});

}

http://jsfiddle.net/cdbzL/1258/