如何用PCRE2正则匹配含“cat”的段落(PHP≥7.3)
解决PHP≥7.3中PCRE2正则匹配含指定单词的段落问题
问题背景
需要匹配文本中所有包含单词cat的段落,段落以两个连续换行分隔,段落内允许单个换行但不能有两个连续换行。之前尝试的((?!\n\n).)*(cat)和\n\n.*(?=cat)cat.*\n\n均无法正常工作,前者无法跨单行匹配,后者仅能捕获单行内容。
正确正则表达式
使用PCRE2的DOTALL模式结合边界匹配,正则如下:
(?s)(?:^|\n\n)(?!\n)(.*?cat.*?)(?=\n\n|$)
正则说明
(?s):开启DOTALL模式,让.可以匹配换行符,支持捕获段落内的单行换行(?:^|\n\n):匹配段落的起始边界,要么是文本开头,要么是两个连续换行(非捕获组,避免多余分组)(?!\n):排除空段落(防止匹配多个连续换行产生的空行)(.*?cat.*?):非贪婪匹配包含cat的内容,确保只捕获当前段落,不会跨到下一个段落(?=\n\n|$):正向预查段落结束边界,要么是两个连续换行,要么是文本结尾
PHP代码示例
$text = <<<'TEXT' Paragraph 1 wepfowfpo fww efwf Paragraph 2 wefwf32321 !@d r33tcat54, 333!.. Paragraph 3 4t4t022 -`121231ere3r3cat342232 $ 4t0g cat rdwd203 $$333 Paragraph 4 222cocdo3 TEXT; // 编译正则 $pattern = '/(?s)(?:^|\n\n)(?!\n)(.*?cat.*?)(?=\n\n|$)/'; // 匹配所有符合条件的段落 preg_match_all($pattern, $text, $matches); // 输出结果 foreach ($matches[1] as $paragraph) { echo $paragraph . "\n"; }
结果验证
运行上述代码后,将输出:
Paragraph 3 4t4t022 -`121231ere3r3cat342232 $ 4t0g cat rdwd203 $$333
为什么之前的正则失效?
((?!\n\n).)*(cat):未开启DOTALL模式,.无法匹配换行,只能捕获单行内容;且未处理段落边界,可能匹配不完整的段落片段\n\n.*(?=cat)cat.*\n\n:同样未支持跨换行匹配,且无法处理文本开头/结尾的段落,仅能捕获被两个换行包裹的单行内容
内容的提问来源于stack exchange,提问作者ZENG
相关产品推荐
相关产品推荐

