加m修饰符仍匹配不到,因m仅影响^和$行为,不改变.的匹配范围;若用.跨行需加s修饰符;含中文必须加u修饰符,否则报错或静默失败。

preg_match 匹配多行时为什么加了 m 还是匹配不到
因为 m 修饰符只影响 ^ 和 $ 的行为,不改变 . 的匹配范围。如果你的模式里用到了 . 去跨行捕获内容(比如 /a.*b/s),但没加 s,那 . 依然跳过换行符,导致中间断开。
常见错误现象:preg_match('/^<div>(.*)$/m', $html, $m) 在多行 HTML 中返回空 —— 因为 <code>.* 不吃换行,^ 和 $ 虽然按行匹配了,但中间内容根本没匹配全。
-
m适用场景:需要对每行单独做“行首/行尾”判断,比如解析配置文件中以[section]开头的段落 -
s适用场景:想让.匹配换行符,比如提取<pre>...</pre>内所有内容(含换行) - 两者可共存:
/pattern/ms表示既按行处理^$,又让.跨行
什么时候必须加 u 修饰符,否则中文直接报错
PHP 7.4 默认使用 PCRE 库,而 PCRE 对 UTF-8 字符串要求显式声明 u 修饰符。不加的话,遇到中文会触发 Compilation failed: invalid UTF-8 string 或静默失败(返回 false)。
典型错误写法:preg_match('/姓名:(.+)/', $text, $m) —— 即使 $text 是 UTF-8 编码,也会失败。
立即学习“PHP免费学习笔记(深入)”;
- 只要正则中出现中文、或目标字符串含中文、或用到 \x{4e00} 这类 Unicode 范围,就必须加
u -
u和s经常一起用:/[\x{4e00}-\x{9fff}]+/us才能正确匹配多行中文段落 - 注意:Windows 环境下文件读取可能默认 GBK,需先
mb_convert_encoding($str, 'UTF-8', 'GBK')
实际提取多行 HTML 片段的推荐写法
比如从一段含换行的 HTML 字符串中提取 <form>...</form>,且内容里有换行和中文:
$pattern = '/<form[^>]*>(.*?)<\/form>/isU';
这里 i 忽略大小写,s 让 . 吃换行,U 避免贪婪匹配到最末尾的 </form>(否则可能跨多个 form)。但要注意:
-
U和?功能重复,选其一即可;U是全局非贪婪,?是局部,更推荐用?显式控制 - 更健壮的写法:
/'<form[^>]*>([\s\S]*?)<\/form>/i'——[\s\S]比.更可靠,不受s修饰符是否启用影响 - 如果要匹配嵌套
<form>(极少见),PCRE 不支持,得换 DOMDocument
性能陷阱:m 修饰符在单行字符串中毫无作用
m 修饰符只有在字符串含 \n 且正则中用了 ^ 或 $ 时才生效。如果目标字符串是单行,加了 m 不报错但纯属冗余;如果没用 ^/$,加了也白加。
容易被忽略的点:
- 用
file_get_contents()读文件时,Windows 换行是\r\n,m仍能识别(PCRE 将\r\n视为一行结束) - 用
str_replace("\r\n", "\n", $str)统一换行符,能减少跨平台歧义 - 调试时可用
var_dump(bin2hex($str))确认换行符真实字节,避免“看着像多行实则没有 \n”



















