在JavaScript中使用单词边界的正则表达式匹配字母数字和非字母数字字符

4
我正在尝试使用JavaScript和正则表达式来高亮一组关键词,但我遇到了一个问题:我的关键词可能包含文字和特殊字符,例如@text #number等。我使用单词边界来匹配和替换整个单词,而不是部分单词(包含在另一个单词中)。
var pattern = new regex('\b '( + keyword +')\b',gi);

这个表达式匹配整个关键词并将它们突出显示,但是如果像“number:”这样的关键词没有被突出显示,则无法匹配。我知道\bword\b可以匹配单词边界,而特殊字符是非字母数字字符,因此不会被上述表达式匹配。你能告诉我使用哪个正则表达式可以实现上述功能吗?
==更新==
对于上述问题,我尝试了Tim Pietzcker建议的以下正则表达式:
expr: (?:^|\\b|\\s)(" + keyword + ")(?:$|\\b|\\s)

上述方法似乎可以匹配包含字母数字和非字母数字字符的整个单词,但是如果一个关键词前后紧跟着HTML标签而没有空格,它将无法突出显示该关键词(例如社会保障号码:*number:< br >*)。我尝试了以下正则表达式,但它会替换关键词之前的HTML标签。
expr: (?:^|\b|\s|<[^>]+>)number:(?:$|\b|\s|<[^>]+>) 

对于关键词number:,后面紧跟着没有空格的<br>(故意添加空格以避免浏览器解释标签),会使该关键词突出显示。

你能否提供一个表达式,忽略整个单词中包含字母数字和非字母数字字符的连续HTML标记。


1
当您有特定的搜索关键字时,为什么要使用正则表达式呢?只需将单词作为字符串进行搜索即可。 - Sebastian Schmidt
tchrist link answer: "请查看此答案,了解使用类似\b和\B边界时需要注意的微妙陷阱。" - Félix Adriyel Gagnon-Grenier
6个回答

2

2021 更新: JS 现在已经支持后顾断言,所以这个答案有点过时了。

好的,你有两个问题:JavaScript 不支持后顾断言,而且 \b 只能找到字母数字字符和非字母数字字符之间的边界。

第一个问题是:对于你的关键词,什么构成单词边界?我的猜测是它必须是一个 \b 边界或空格。如果是这样的话,你可以搜索:

"(?:^|\\b|\\s)(" + keyword + ")(?:$|\\b|\\s)"

当然,像@number#这样的关键字周围的空格字符也将成为匹配的一部分,但也许突出显示这些并不是什么问题。在其他情况下,即如果有实际的单词边界可以匹配,则空格不会成为匹配的一部分,因此在大多数情况下应该可以正常工作。
你感兴趣的实际单词将在回溯引用#1中,因此如果可以单独突出显示它,那就更好了。
编辑: 如果除了空格以外的其他字符可能在关键字之后/之前出现,那么我认为您可以做的唯一一件事(如果您被限制使用JavaScript)是:
  1. 检查您的关键字是否以alnum字符开头。
  2. 如果是,请将\b前缀到您的正则表达式中。
  3. 检查您的关键字是否以alnum字符结尾。
  4. 如果是,请将\b附加到您的正则表达式末尾。
所以,对于“keyword”,请使用“\bkeyword\b”;对于“number:”,请使用“\bnumber:”;对于“@twitter”,请使用“@twitter\b”。

以上似乎可以用来获取包含字母数字和非字母数字字符的整个单词的匹配,但是每当一个关键词在其前面或后面有连续的HTML标签时,它就无法突出显示该关键词(例如:社会保障号码:<br>)。您能告诉我如何忽略这些HTML标记(可能是任何标记)吗?我尝试了以下正则表达式,但它替换了关键词之前的HTML标记。 - Bhupen
表达式:(?:^|\b|\s|<[^>]+>)数字:(?:$|\b|\s|<[^>]+>) - Bhupen

1

我们需要查找一个子字符串,两侧都有空格字符。如果 JavaScript 支持 lookbehind,则会像这样:

var re = new RegExp('(?<!\\S)' + keyword + '(?!\\S)', 'gi');

但这并行不通,(虽然在Perl和其他脚本语言中可以)。相反,我们需要将前导空格字符(或字符串开头)包含在匹配的开始部分,并可选择地将我们真正寻找的内容括号捕获到 $1 中:

var re = new RegExp('(?:^|\\s)(' + keyword + ')(?!\\S)', 'gi');

请注意,任何匹配开始的真实位置将在re.exec(string)返回的.index属性返回的位置之后一个字符,如果您要访问匹配的字符串,则需要使用.slice(1)删除第一个字符或直接访问捕获的内容。

0

也许你想要做的是

'\b\W*(' + keyword + ')\W*\b'

0

前瞻和后顾是你的答案:"(?=<[\s^])" + keyword + "(?=[\s$])"。括号中的位不包含在匹配中,因此请在其中包含关键字中不允许的任何字符。


抱歉,我的错误...JavaScript不支持lookbehind(尽管它出于某种原因支持lookahead)。请忽略。 - Nathan MacInnes

0

试试这个,应该可以工作...

var pattern = new regex(@"\b"+Regex.escape(keyword)+@"\b",gi);

0
正如Tim所指出的那样,\b是一些棘手的东西,它们的工作方式与人们通常认为的不同。阅读this answer以获取有关此问题的更多详细信息以及您可以采取的措施。
简而言之,这是一个左边界:
(?(?=\w)(?<!\w)|(?<!\W))

这是右边的边界:

(?(?<=\w)(?!\w)|(?!\W))

人们总是认为有空格的问题,但实际上并没有。不过,现在你知道了真正的定义,很容易将其融入其中。可以将\w\W替换为上述两个模式中的\s\S。或者可以在else块中添加空格感知。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接