使用字符串变量即时创建RegExps


138

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

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);
}

Answers:


215

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

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

评估为

zilla

31
/在使用此格式时也省略正则表达式分隔符。
cdhowie 2010年

111

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

并不是的!该示例仅替换的第一个匹配项string_to_replace。通常,您希望替换所有出现的情况,在这种情况下,必须将字符串转换为全局(/.../g)RegExp。您可以使用new RegExp构造函数从字符串执行此操作:

new RegExp(string_to_replace, 'g')

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

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

还要注意,当您使用RegExp in时replace(),替换字符串现在也具有特殊字符$。如果要$在替换文本中包含文字,也必须对此进行转义!

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

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

现在,您可以使用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);

10

正如其他人所说,请使用new RegExp(pattern, flags)此操作。值得注意的是,您将字符串文字传递给此构造函数,因此每个反斜杠都必须转义。例如,如果您想让正则表达式与反斜杠匹配new RegExp('\\\\'),则需要说,而正则表达式的文字只需是/\\/。根据您打算如何使用它,您应该警惕在没有充分预处理(转义特殊字符等)的情况下将用户输入传递给该函数,否则,您的用户可能会得到一些非常意外的结果。


3
这个答案虽然不是最详细的,但确实提到了一个关键的细节,我只是停留了一个小时:逃避任何特殊的顺序。例如,我正在搜索以某个术语开头的单词,所以我需要的正则表达式是/\b[term]\B/,但是在构造它时,我需要调用new RegExp("\\b"+ term + "\\B")。小而重要的差异,并且很难发现,因为直接将其用作正则表达式确实可以按预期工作。
Byson 2015年


0

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

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/


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.