正则表达式中\b和\B的区别

162

我正在阅读一本有关正则表达式的书,我遇到了这个例子:\b

The cat scattered his food all over the room.

使用正则表达式 - \bcat\b 可以匹配单词 cat 但不匹配在 scattered 中的 cat

对于 \B,作者使用了下面的例子:

Please enter the nine-digit id as it

appears on your color - coded pass-key.

使用正则表达式 \B-\B 匹配单词 color - coded 中的 -。然而使用 \b-\b 则会匹配 nine-digitpass-key 中的 -

为什么在第一个例子中我们使用 \b 来分离 cat 而在第二个例子中使用 \B 来分离 - 呢?在第二个例子中使用 \b 的话会和之前的例子产生相反的效果。

请给我解释一下这两者之间的区别。

编辑:还有,有人可以给我一个新的例子来解释吗?


你在读什么书?或许可以帮助其他人学习正则表达式。 - Yohanim
3
@YohanesAI 这本书是Ben Forta所著的《Sams Teach Yourself Regular Expressions in 10 Minutes》。 - stirredo
10个回答

140
混淆源于你认为 \b 匹配空格(可能是因为 "b" 暗示着 "blank")。
\b 匹配一个单词的开头或结尾处的空字符串。\B 匹配不在单词开头或结尾处的空字符串。关键在于 "-" 不是单词的一部分。所以 <left>-<right> 匹配 \b-\b,因为连字符两侧都有单词边界。另一方面,对于 <left> - <right>(注意空格),连字符两侧都没有单词边界。单词边界向左和向右各多了一个空格。
另一方面,在搜索 \bcat\b 时,单词边界的行为更符合直觉,它按预期匹配 " cat "。

2
是的,我确实将\b与空格混淆了。但是,我仍然感到有点困惑。我可以再请你举一个例子吗? - stirredo
4
关键是“-”不被视为单词的一部分,同样,“!”也不是单词的一部分。因此,\b!\b可以匹配"uunet!iamold",但不能匹配 "Wow! You are." 您可以在 http://regexpal.com 上尝试这些内容。 - andrewdski
2
只是补充一下,正则表达式中的单词由字母(a-z和A-Z)、数字和“_”[下划线]组成。其他字符都不属于单词。 - Maralc
1
有人可以详细解释一下这行代码吗?\B匹配不在单词开头或结尾的空字符串。 - Arun Gowda
1
我会更加强调边界,可能是在排版上,更好的方法是将正确提示(b代表boundary)移动到答案的顶部。 - Wolf
显示剩余2条评论

98

\b是一个零宽度的单词边界,具体来说:

匹配单词字符(任何由\w匹配的内容)和非单词字符(任何由[^\w]或\W匹配的内容)之间的位置,并且如果字符串的第一个和/或最后一个字符是单词字符,则也匹配字符串的开头和/或结尾。

例如:.\b匹配abc中的c

\B是一个零宽度的非单词边界,具体来说:

匹配两个单词字符之间的位置(即\w\w之间的位置),以及两个非单词字符之间的位置(即\W\W之间的位置)。

例如:\B.\B匹配abc中的b

有关更多正则表达式信息,请参见regular-expressions.info


15
+1是因为零宽度是定义的重要组成部分。如果不是零宽度,那么匹配模式中的单词/非单词字符也会被捕获。 - Ben Hocking
5
换句话说,\B匹配\W和\W之间或\w和\w之间的位置,但不匹配\W和\w之间的位置。 - user3458
1
该回答已经被添加到Stack Overflow正则表达式FAQ中的“锚点”一节。 - aliteralmind
继续跟进这个问题:@Bohemian,为什么在JS中"abc def".match(/\b./)返回['a']而不是[http://www.regular-expressions.info/refwordboundaries.html](您的来源:regex.info)所说的`['a', ' ', 'd']`? - steviesh
1
@stephenhuh string.match() 只返回第一个匹配项,除非你添加 global 标志 g"abc def".match(/\b./g) 返回 ['a', ' ', 'd'] - Bohemian
1
我认为这是更好的答案。它应该被接受,因为它解决了困惑。在这里还有很多需要学习的地方。 - Wolf

69

以另一个例子为例:

考虑这是一个字符串,要搜索的模式是“cat”:

text = "catmania thiscat thiscatmaina";

现在定义如下:

'\b' 查找/匹配单词的开头或结尾处的模式。

'\B' 不查找/匹配单词的开头或结尾处的模式。

不同情况:

情况1:在每个单词的开头

result = text.replace(/\bcat/g, "ct");

现在,结果是“ctmania thiscat thiscatmaina”

情况2:在每个单词的结尾

result = text.replace(/cat\b/g, "ct");

现在,结果是“catmania thisct thiscatmaina”

情况3:不在开头

result = text.replace(/\Bcat/g, "ct");

现在,结果是“catmania thisct thisctmaina”

情况4:不在结尾

result = text.replace(/cat\B/g, "ct");

现在,结果是“ctmania thiscat thisctmaina”

情况5:既不在开头也不在结尾

result = text.replace(/\Bcat\B/g, "ct");

现在,结果是“catmania thiscat thisctmaina”

希望这有所帮助 :)


3
请纠正我,如果我错了,请问,在使用\bcat\b时,如果我们的字符串是,例如:"catcat is my cat" => 第一个单词(catcat)会符合这个条件。对吗? - Kosem
3
@Kosem 这是一个好问题,让我更好地学习了 \b。我的理解是,第一个单词不匹配的原因是,使用 \bcat\b 表示 cat 必须被单词边界包围。catcat 以单词边界开始,找到了第一个内部的 cat [我们仍然遵守正则表达式],但是尾部的 \b 强制要求在 catcat 的第一个 t 之后必须有另一个单词边界,这不是情况,因为 catcat 中的第二个 c 是另一个单词字符 [= 单词继续]。跳过 catcat 的第二个 cat 的原因类似。 - Antonino

11

元字符\b是一种锚点,类似于插入符号(^)和美元符号($)。它匹配的位置称为“单词边界”,这种匹配是零长度的。

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

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

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

来源:http://www.regular-expressions.info/wordboundaries.html


6

来源 © 版权 RexEgg.com

单词边界:\b*

\b匹配的是一个单词字符(通常是字母、数字或下划线,但不同引擎有所变化)与另一侧不是单词字符的位置(例如字符串的开头或空格字符)。

因此,正则表达式\bcat\b将匹配“黑猫”中的“cat”,但不会匹配“猫弛缓症”、“汤姆猫”或“证书”中的“cat”。如果移除其中一个边界,则\bcat将匹配“鲶鱼”中的“cat”,而cat\b将匹配“汤姆猫”中的“cat”,但反之则不行。当然,两者都将匹配单独的“cat”。

非单词边界:\B

\B匹配\b不匹配的所有位置。因此,它可以匹配:

✽ 当两侧均不是单词字符时,例如在字符串 $=(@-%++) 中的任何位置(包括字符串的开头和结尾)

✽ 当两侧都是单词字符时,例如在“Hi!”中的H和i之间

这可能看起来不是很有用,但有时\B正是您想要的。例如:

✽ \Bcat\B 将查找完全被单词字符包围的“cat”,如在“证书”中,但不会匹配单独的“cat”或单词的开头或结尾。

✽ cat\B 将在“证书”和“鲶鱼”中都查找到“cat”,但不会匹配“汤姆猫”或单独的“cat”。

✽ \Bcat 将在“证书”和“汤姆猫”中都查找到“cat”,但不会匹配“鲶鱼”或单独的“cat”。

✽ \Bcat|cat\B 将在嵌入式情况下查找“cat”,例如在“证书”、“鲶鱼”或“汤姆猫”中,但不会匹配单独的“cat”。


4

\b 用作单词边界

word = "categorical cat"

在上面的单词中找到所有的“cat”(不包括 \b)。
re.findall(r'cat',word)
['cat', 'cat']

使用 \b

re.findall(r'\bcat\b',word)
['cat']

3

4
\B不等同于[^\b]。字符类([...][^...])消耗一个字符,而像\b\B这样的零宽断言并不会消耗任何东西。如果您将\b放在字符类中,则其含义完全不同:[\b]匹配退格符,而[^\b]匹配除了退格符之外的任何字符。 实际上,\B等价于 (?!\b) - Alan Moore
@Alan 谢谢,你完全正确——我今天早上写那个的时候还没醒过神来。已修复。 - Matt Ball
4
但为什么有人想要匹配一个退格键,这超出了我的理解范围。 :D - Alan Moore

3

让我们拿一个字符串:

XIX IXI XX X I II IIXX XXII I-I X-X -X X- X-I I-X -X- -I-X -X-I I-X- X-I- X_X _X-

注意:下划线(_)在此情况下不被视为特殊字符。

  1. /\bX\b/g 应该以特殊字符或空格开头和结尾

XIX IXI XX X I II IIXX XXII I-I X-X -X X- X-I I-X -X- -I-X -X-I I-X- X-I- X_X _X-


  1. /\bX/g 应该以特殊字符或空格开头

XIX IXI XX X I II IIXX XXII I-I X-X -X X- X-I I-X -X- -I-X -X-I I-X- X-I- X_X _X-


  1. /X\b/g 应该以特殊字符或空格结尾

XIX IXI XX X I II IIXX XXII I-I X-X -X X- X-I I-X -X- -I-X -X-I I-X- X-I- X_X _X-


  1. /\BX\B/g
    不应以特殊字符或空格开头和结尾

XIX IXI XX X I II IIXX XXII I-I X-X -X X- X-I I-X -X- -I-X -X-I I-X- X-I- X_X _X-


  1. /\BX/g 不应以特殊字符或空格开头

XIX IXI XX X I II IIXX XXII I-I X-X -X X- X-I I-X -X- -I-X -X-I I-X- X-I- X_X _X-


  1. /X\B/g 不应以特殊字符或空格结尾

XIX IXI XX X I II IIXX XXII I-I X-X -X X- X-I I-X -X- -I-X -X-I I-X- X-I- X_X _X-


  • /\bX\B/g 应该以特殊字符或空格开头而不是结尾
  • XIX IXI XX X I II IIXX XXII I-I X-X -X X- X-I I-X -X- -I-X -X-I I-X- X-I- X_X _X-


  • /\BX\b/g 不应该以特殊字符或空格开头,但应该以它们结尾
  • XIX IXI XX X I II IIXX XXII I-I X-X -X X- X-I I-X -X- -I-X -X-I I-X- X-I- X_X _X-


    2
    https://www.regular-expressions.info/wordboundaries.html所述:

    \b有三个符合单词边界的不同位置:

    1. 如果第一个字符是单词字符\w, 则在字符串中第一个字符之前。
    2. 如果最后一个字符是单词字符\w, 则在字符串中最后一个字符之后。
    3. 在字符串中两个字符之间,其中一个是单词字符\w,另一个不是单词字符\W
    为了更好地理解\b,我想考虑使用箭头将字符串上的单词边界标记出来。请参见以下链接获取字符串的数组可视化: 'THE CAT SCATTERED''THE NINE-DIGIT COLOR - CODED PASS-KEY'
    对于字符串THE CAT SCATTERED
    • 根据以上提到的条件 1,位于索引0的单词边界被分配。
    • 根据条件 2,位于索引16的单词边界被分配。
    • 根据条件 3,位于索引2、4、6和8的单词边界被分配。
    对于字符串THE NINE-DIGIT COLOR - CODED PASS-KEY
    • 根据条件 1,位于索引0的单词边界被分配。
    • 所有剩余的单词边界都是根据条件 3分配的。请注意,由于字符串以一个不是单词字符\w的'.'字符结尾,因此不适用条件 2
    非单词边界\B也可以使用以下条件进行类似的数组可视化:
    (来源:@Ganesh M S's的答案)

    \B 匹配所有 \b 不匹配的位置,即:

    1. 当两侧都不是单词字符(即两侧都是 \W)时,例如在字符串 $=(@-%++) 中的任何位置(包括字符串的开头和结尾)。
    2. 当两侧都是单词字符 \w 时,在 Hi! 中 H 和 i 之间。

    0

    \B 不是 \b,例如: negative \b

    pass-key 这里的 - 旁边没有单词边界,因此它与第一个示例中的 \B 匹配。而在 cat 旁边有单词边界,所以它与 \b 匹配。

    其他规则也适用。 \W\w 的反义词,\UPPER CASE\LOWER CASE 的反义词。


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