PHP中preg_replace正则删除字符串末尾单词的逻辑及$1作用疑问
正则匹配到「 fox」的完整过程
正则末尾带有$字符串末尾锚点,引擎会从左到右遍历字符串,寻找能完整匹配整个正则规则、且匹配结束位置刚好落在字符串末尾的片段,不满足锚点要求的匹配会被回溯舍弃,最终匹配路径如下:
- 优先定位所有非单词字符的位置作为潜在匹配起点:示例原字符串为
The quick brown fox,所有非单词字符就是四个单词之间的三处空格。 - 从每个空格位置开始向后验证全规则匹配:
- 以
The后的空格为起点时,匹配完quick及后续内容后,离字符串末尾仍有brown fox的距离,无法满足结尾锚定要求,匹配失效。 - 以
quick后的空格为起点时,匹配完brown及后续内容后,离字符串末尾仍有fox的距离,同样无法满足结尾锚定要求,匹配失效。 - 以
brown后的空格为起点时,所有规则全部验证通过:- 开头的
\W匹配起点位置的空格,确保从单词边界开始匹配,不会截断前序单词的内容 - 后续
\w+匹配连续的单词字符fox - 后续
\s*因为到达字符串末尾,匹配0个空白字符 - 最后的
(\W*)$因为到达字符串末尾,匹配0个非单词字符,同时满足字符串末尾锚点要求
- 开头的
- 以
- 最终整个匹配到的片段就是“起点分隔空格+fox”,也就是观测到的
fox。
替换值中
$1的作用逻辑 首先明确preg_replace的核心规则:正则命中的整段子串,都会被替换为替换参数指定的内容。
如果直接把替换值设为空字符串,虽然在当前示例中能达到删除最后一个单词的效果,但这段正则的设计本身是为了兼容更通用的场景:
- 捕获组
(\W*)的作用是留存最后一个单词后面、字符串末尾位置的所有非单词字符内容。 - 举个实际场景的例子:如果原字符串是
The quick brown fox!(单词末尾带感叹号),此时正则命中的整段子串是fox!,其中捕获组$1会捕获到末尾的!。 - 这时候如果用空字符串作为替换值,会连带把末尾的感叹号一起删掉,得到
The quick brown;但如果用$1作为替换值,会把命中的fox!替换成捕获组留存的!,最终得到The quick brown!——既删除了最后一个单词和它前面的分隔空格,又完整保留了字符串末尾的标点、特殊符号等非单词内容,这才是这段正则的设计目的。
在给出的示例中,因为原字符串末尾没有额外的非单词字符,捕获组$1的内容是空字符串,所以替换后看起来和直接删除整段命中内容的效果完全一致,容易让人产生“替换值为啥不是空”的疑惑。
内容的提问来源于stack exchange,提问作者Light Yagami
相关产品推荐
相关产品推荐

