? 是量词,表示前项出现0次或1次;?? 是惰性模式,修饰其他量词;匹配字面?需转义为?;字符类中?无需转义;动态构造正则时注意反斜杠转义。

问号 ? 在正则中默认表示“前面的元素出现 0 次或 1 次”
它是一个量词(quantifier),作用对象是紧邻其前的单个字符、分组或字符类。比如 a? 匹配空字符串或一个 a;(ab)? 匹配空字符串或整个 ab;[0-9]? 匹配一位数字或不匹配任何数字。
注意:它不匹配字面义的问号字符——要匹配真正的 ?,必须转义为 ?。
?? 是非贪婪(惰性)模式,不是语法错误
单独一个 ? 是量词;当它紧跟在另一个量词(如 *、+、{2,5})后面时,就变成修饰该量词的“惰性开关”。例如:
-
a*?:匹配尽可能少的a(哪怕 0 个),而不是默认的“尽可能多” -
.*?常用于提取 HTML 标签间内容,避免跨标签贪婪匹配 -
href="(.*?)"能正确捕获第一个双引号内的内容,而href="(.*)"可能吞掉后续引号
常见误用:忘记转义字面问号或混淆 ? 和 ?
典型错误现象:Version: 1.2.3? 这样的字符串想精确匹配末尾的 ?,却写成 Version: d+.d+.d+? ——这里末尾的 ? 会被解释为“前面的 d+ 出现 0 或 1 次”,完全偏离本意。
正确写法应是:Version: d+.d+.d+?(末尾 ? 才匹配字面问号)。
10分钟内自己学会PHP其中,第1篇为入门篇,主要包括了解PHP、PHP开发环境搭建、PHP开发基础、PHP流程控制语句、函数、字符串操作、正则表达式、PHP数组、PHP与Web页面交互、日期和时间等内容;第2篇为提高篇,主要包括MySQL数据库设计、PHP操作MySQL数据库、Cookie和Session、图形图像处理技术、文件和目录处理技术、面向对象、PDO数据库抽象层、程序调试与错误处理、A
其他易错点:
- 在字符类中(
[?*+]),?不需要转义,它就是普通字符 - 在某些正则引擎(如 JavaScript)中,
?后面不能直接跟未闭合的括号,否则报Invalid regular expression: unmatched parenthesis - 使用
new RegExp("a?")动态构造时,字符串中的反斜杠需双写:new RegExp("a\?")才能生成字面?
Python 中 re.search 和 re.findall 对 ? 的行为一致,但结果可能不同
贪婪与惰性只影响匹配长度,不影响是否能匹配成功。但对 findall 影响明显:
import re text = "aabbcc" print(re.findall(r"a+", text)) # ['aa'] print(re.findall(r"a+?", text)) # ['a', 'a'] ——每个 a 单独匹配一次
这是因为 a+? 在每次尝试时都优先取最短有效匹配,导致引擎多次启动匹配过程。
真正容易被忽略的是:惰性量词仍受整体匹配位置约束。比如 ^a+?b 在 aab 中只会匹配整个 aab,不会因为 +? 就停在第一个 a 后——因为那样无法满足结尾的 b。









