为什么`=`或```在使用`\ b`时打破PHP正则表达式?

gcb*_*gcb 10 php regex

这是在阅读如何指定"空格或字符串结尾"和"空格或字符串开头"之后的后续操作

从那里开始,它表示匹配短语中的单词的方法.我甚至可以添加一些其他解决方案.但是,只要添加="添加,它就会停止工作.为什么?

我要去寻找stackoverflow,取而代之的是OK使用preg_replace()

preg_replace('/\bstackoverflow\b/', 'OK', $input_line)

input:
1: stackoverflow xxx
2: xxx stackoverflow xxx
3: xxx stackoverflow
result:
1: OK xxx
2: xxx OK xxx
3: xxx OK
Run Code Online (Sandbox Code Playgroud)

现在,如果我将其更改为匹配stackoverflow="",它将停止工作.

preg_replace('/\bstackoverflow=""\b/', 'OK', $input_line)

input:
1: stackoverflow="" xxx
2: xxx stackoverflow="" xxx
3: xxx stackoverflow=""
result:
1: stackoverflow="" xxx
2: xxx stackoverflow="" xxx
3: xxx stackoverflow=""
Run Code Online (Sandbox Code Playgroud)

如果我使用我的正则表达式,也会发生同样的情况:/\bstackoverflow=\b//\bstackoverflow"\b/.我已经检查了手册,如果="有特殊字符,它们不是.但我甚至尝试过/\bstackoverflow\=\"\"\b/

这是为什么?

在该示例中,删除\b也将解决它,但它也将匹配nostackoverflow=""not我不想要的.

我也尝试过替代\b这样的[ ^]( |^).有趣的是[ ^](空间或线的起点)不适用于线的开头,只有空间.但( |^)两者都可以正常工作.

mik*_*n32 5

问题是你使用\b哪个是"单词边界".它是一个占位符(^\w|\w$|\W\w|\w\W),在哪里\w是"单词"字符[A-Za-z0-9_],\W而相反.问题是a "与"单词"字符不匹配,因此不符合边界条件.

尝试使用\s替代,它将匹配任何空格字符.

(?:^|\s)stackoverflow=""(?:\s|$)
Run Code Online (Sandbox Code Playgroud)

除了^在类的开头用作否定运算符和-作为范围运算符之外,不解释类中的字符.这就是为什么[ ^]不适合你.它正在寻找文字^.

$ php -a
Interactive shell

php > $input_line='
php ' stackoverflow="" xxx
php ' xxx stackoverflow="" xxx
php ' xxx stackoverflow=""
php ' ';
php > echo preg_replace('/(?:^|\s)stackoverflow=""(?:\s|$)/', 'OK', $input_line);
OKxxx
xxxOKxxx
xxxOK
Run Code Online (Sandbox Code Playgroud)

https://regex101.com/r/nP2aB8/1

  • 单词边界`\ b`相当于`(?:(?<!\ w)(?=\w)|(?<=\w)(?!\ w))`这意味着:*向前, (至少)一个字符是一个单词字符,在后面,我们找不到单词字符(字符不是单词字符,或者它是字符串的开头)*.**或** - *在后面,有(至少)一个字符是一个单词字符,并且在前面,我们找不到单词字符(要么字符不是单词字符,要么它是结束字符串).* (2认同)

Wik*_*żew 5

背景

从正则表达式.info词边界页面

元字符\b是像插入符号和美元符号一样的锚点。它称为“词边界”的位置匹配。这个匹配是零长度的

三个不同的位置可以作为单词边界:
-在字符串中的第一个字符之前,如果第一个字符是单词字符。
-在字符串的最后一个字符之后,如果最后一个字符是单词字符。
-在字符串中的两个字符之间,其中一个是单词字符,另一个不是单词字符

来自nhahtdh 帖子的一个很好的解释:

一个词边界\b相当于:

(?:(?<!\w)(?=\w)|(?<=\w)(?!\w))
Run Code Online (Sandbox Code Playgroud)

意思是:

  • 就在前面,(至少)有一个字符是单词字符,在后面,我们找不到单词字符(该字符不是单词字符,或者是字符串的开头)。

    或者

  • 紧随其后的是(至少)一个是单词字符的字符,而在正前方,我们找不到单词字符(该字符不是单词字符,或者是字符串的结尾)。

你的正则表达式有什么问题

之所以\b不合适,是因为它需要在其后/前出现一个单词/非单词字符,这取决于\b. 当您动态构建正则表达式时,您不知道使用哪一个,\B或者\b. 对于您的情况,您可以使用'/\bstackoverflow=""\B/',但它需要附加智能单词/非单词边界。但是,有一种更简单的方法:使用否定环顾

解决方案

(?<!\w)stackoverflow=""(?!\w)
Run Code Online (Sandbox Code Playgroud)

正则表达式演示

正则表达式包含负环视而不是单词边界。的(?<!\w),如果有一个字字符前回顾后失败的比赛stackoverflow="",并且(?!\w)如果先行失败的比赛stackoverflow=""后跟一个字字符。

单词速记字符类\w匹配的内容取决于您是否启用了 Unicode 修饰符/u。没有它,a\w只匹配[a-zA-Z0-9_]. 您可以使用环视设置进一步的限制。

演示

PHP 演示

$re = '/(?<!\w)stackoverflow=""(?!\w)/'; 
$str = ",stackoverflow=\"\" xxx\nxxx stackoverflow=\"\" xxx\nxxx stackoverflow=\"\"\nstackoverflow=\"\" xxx"; 
echo preg_replace($re, "NEW=\"\"", $str);
Run Code Online (Sandbox Code Playgroud)

注意:如果您将字符串作为变量传递,请记住使用以下命令对其中的所有特殊字符进行转义preg_quote

$re = '/(?<!\w)' . preg_quote($keyword, '/') . '(?!\w)/'; 
Run Code Online (Sandbox Code Playgroud)

在这里,请注意 的第二个参数preg_quote,即/正则表达式分隔符字符。