匹配可能有特殊字符的单词

时间:2013-12-05 23:29:15

标签: javascript regex

我正在尝试替换字符串中给定单词的所有出现,但该单词可能包含需要转义的特殊字符。这是一个例子:

  

ERA是每九个投手放弃的跑步的平均值   投球局。同时,ERA +,经过调整的ERA,是一名投手   根据投手的棒球场获得跑动平均值(ERA)(以防万一)   球场有利于投手或投手)和投手的ERA   联赛。

我希望能够做到以下几点:

string = "The ERA..." // from above
string = string.replaceAll("ERA", "<b>ERA</b>");
string = string.replaceAll("ERA+", "<u>ERA+</u>");

没有ERA和ERA冲突。我一直在使用protoype replaceAll posted previously以及在SO上的其他地方找到的正则表达式(我似乎无法在历史记录中找到链接)

String.prototype.replaceAll = function (find, replace) {
    var str = this;
    return str.replace(new RegExp(find.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'g'),     replace);
};

function loadfunc() {
    var markup = document.getElementById('thetext').innerHTML;
    var terms = Object.keys(acronyms);
    for (i=0; i<terms.length; i++) {
        markup = markup.replaceAll(terms[i], '<abbr title=\"' + acronyms[terms[i]] + '\">' + terms[i] + '</abbr>');
    }
    document.getElementById('thetext').innerHTML = markup;
}

基本上代码的作用是在缩放时添加标记以包含鼠标悬停时的定义。问题是当前的正则表达式太松散了。我以前的尝试部分工作,但未能在ERA和ERA +之类的东西之间产生差异,或者完全跳过“K / 9”或“IP / GS”之类的东西(这应该是匹配的,而不是“IP”或“GS”单独)

我应该提一下,首字母缩略词是一个看起来像的数组:

var acronyms = {
    "ERA": "Earned Run Average: ...",
    "ERA+": "Earned Run Average adjusted to ..."
};

另外(尽管这很明显)'thetext'是一个包含一些文本的虚拟div。 loadfunc()函数从<body onload="loadfunc()">

执行

谢谢!

2 个答案:

答案 0 :(得分:1)

好的,在查看你的jsFiddle后,这可以解决很多问题。

我认为您将获得的最佳效果是搜索以大写字母开头的整个单词,其中可能包含/%。这样的事情:([A-Z][\w/%]+)

警告:无论你如何做到这一点,如果你在浏览器中这样做(例如你无法更新原始数据),那将是一个过程密集型。

你可以像这样实现它:

var repl = str.replace(/([A-Z][\w\/%]+)/g, function(match) {
    //alert(match);
    if (match in acronyms)
        return "<abbr title='" + acronyms[match] + "'>" + match + "</abbr>";
    else
        return match;
});

这是一个有效的jsFiddle:http://jsfiddle.net/remus/9z6fg/

请注意,jQuery不是必需的,只是在这种情况下使用jQuery以便于更新jsFiddle中的DOM。

答案 1 :(得分:0)

您希望使用具有负前瞻的正则表达式:

string.replace(/\bERA(?!\+)\b/g, "<b>ERA</b>");

string.replace(/\bERA\+/g, "<u>ERA+</u>");

为了更好的衡量,添加了零宽度字边界\b,因此您不会意外地匹配“BERA”等字符串。

另一个想法是将最长的密钥列表排序为最小的密钥。这样你肯定会在'ERA'之前替换所有'ERA +',所以没有子串冲突。