教程 > 正则表达式 > 锚点 阅读:89

单词边界

单词边界


元字符\b是类似于^$锚点。它在称为“单词边界”的位置匹配。此匹配也是为零长度

有三个不同的位置可以作为单词边界:

  • 如果字符串中的第一个字符是单词字符,则在字符串中第一个字符之前。
  • 如果字符串中的最后一个字符是单词字符,则在字符串的最后一个字符之后。
  • 字符串中的两个字符之间,其中一个是单词字符,另一个不是单词字符。

简而言之:\b允许您使用\b word\b形式的正则表达式执行“仅整个单词”搜索。“单词字符”是可用于形成单词的字符。所有不是“文字字符”的字符都是“非文字字符”。

究竟哪个字符是文字字符取决于我们使用的正则表达式引擎。在大多数形式中,与速记字符类\w匹配的字符是被单词边界视为单词字符的字符。Java是一个例外。Java支持\b而不是\w的Unicode 。

除以下讨论的正则表达式引擎之外,大多数正则表达式引擎仅具有一个同时在单词之前和单词之后都匹配的元字符。这是因为字符之间的任何位置都不能同时位于单词的开头和结尾。仅使用一个运算符就可以使您更轻松地工作。 由于数字被认为是单词字符,因此\b3\b可用于匹配数字3,但是不能匹配属于一个较大数的一部分的3,例如 33,43,53等都是不能匹配的。因此,“ \b在字母数字序列之前和之后匹配”,这要比说“在单词之前和之后”更准确。

\B\b的否定。\B\b不匹配的每个位置匹配。实际上,\B在两个单词字符之间的任何位置以及两个非单词字符之间的任何位置都匹配。

正则表达式引擎内核


下面让我们看一下,将正则表达式\bis\b应用于字符串This regex is beautiful会发生什么。引擎将第一个token \b 应用于字符串的第一个字符T。由于此token的长度为零,因此将检查字符之前的位置。\b在这里匹配,因为T是单词字符,而T之前的字符是字符串开头之前的void。引擎继续下一个token:i 。引擎不会前进到字符串中的下一个字符,因为前一个regex token \b的长度为零。i不匹配T ,因此引擎在下一个字符位置重试第一个token。           

\b在T和h之间的位置不能匹配。它在h和i之间也不能匹配, 在 i 和 s之间也不能匹配。

字符串中的下一个字符是空格。\b在这里匹配,因为空格不是单词字符,而前一个i是字符。同样,引擎继续输入与空格不匹配的i 。

前进一个字符并使用第一个正则表达式token重新开始,重复上面的步骤,直到\b在空格和字符串中的第一个i之间匹配。继续,正则表达式引擎发现i匹配i,而s匹配s 。现在,引擎尝试在s之后的位置匹配第二个\ b 。因为该位置是空格,所以此操作成功。

该正则表达式引擎已成功匹配的字符串is在我们的字符串中,跳过字符i和s的前一次发生。如果我们使用正则表达式is,它匹配到的是This中的is。

Tcl单词边界


如上所述,大多数正则表达式都支持单词边界。值得注意的例外是POSIX和XML Schema风格,它们根本不支持单词边界。Tcl使用不同的语法。

在Tcl中,\b匹配一个退格字符,就像大多数正则表达式(包括Tcl的)中的\x08一样。\B与Tcl中的单个反斜杠字符匹配,就像所有其他正则表达式中的\一样(Tcl也是如此)。

Tcl使用字母“ y”代替字母“ b”来匹配单词边界。\y在任何单词边界位置都匹配,而\Y在不是单词边界的任何位置都匹配。这些Tcl regex token与Perl中的regex的\b和\B完全匹配。他们不区分单词的开头和结尾。

Tcl还有两个单词边界标记,它们确实在单词的开头和结尾之间进行区分。\m仅在单词开头匹配。也就是说,它在任何位置匹配,该位置在其左侧具有非单词字符,而在其右侧具有单词字符。如果字符串中的第一个字符是单词字符,则它也匹配字符串的开头。\M仅在单词结尾处匹配。它在任何在其左侧具有文字字符且在其右侧具有非文字字符的位置匹配。如果字符串中的最后一个字符是单词字符,那么它也匹配字符串的末尾。

JGsoft引擎是唯一支持Tcl样式的单词边界(除了Tcl本身)的正则表达式引擎。     

在大多数情况下,缺少\m\M 标记不是问题。\yword\y就像\mword\ M一样,找到“单词”的“仅整个单词”出现。\Mword\m任何地方匹配都不会去匹配,因为\M永远不会在单词字符后面的位置匹配,并且\m永远不会在单词前的位置匹配。如果您的正则表达式需要匹配\y之前或之后的字符,则可以轻松地在正则表达式中指定这些字符应为文字字符还是非文字字符。如果要匹配任何单词,\y\w+\y给出的结果与\m.+\M相同。使用\w代替点.会自动将第一个\y限制为单词的开头,而第二个\y则限制为单词的结尾。请注意,\y.+\y将不起作用。此正则表达式匹配目标字符串中每个单词以及单词之间每个非单词字符序列。也就是说,如果您的正则表达式支持\m和\M ,则正则表达式引擎可以应用\m\w+\M,其速度比\y\w+\y快一点,具体取决于其引擎内部的优化。

如果您正则表达式支持前瞻断言和后瞻断言,您可以使用(?<!\w)(?=\w)来模仿Tcl的\m;使用(?<=\w)(?!\w)来模仿\M。尽管看起来比较冗长,但这些环视结构与Tcl的单词边界完全相同。

如果你的正则只有有前瞻断言但没有后瞻断言,也有Perl样式字边界,你可以使用\b(?=\w)来模仿Tcl的\m和\b(?!\w)效仿\M。\b在单词的开头或结尾匹配,并且检查下一个字符是否是单词的一部分。如果是的话,那就是一个单词的开头。否则,只能说拜拜了。

查看笔记

扫码一下
查看教程更方便