PHP 日本大会 2024

重复

重复由量词指定,量词可以跟在以下任何项目之后:

  • 单个字符,可能已转义
  • `.` 元字符
  • 字符类
  • 反向引用(参见下一节)
  • 带括号的子模式(除非它是断言 - 参见下文)

通用重复量词通过在花括号(大括号)中给出两个用逗号分隔的数字来指定允许匹配的最小和最大数量。数字必须小于 65536,并且第一个数字必须小于或等于第二个数字。例如:z{2,4} 匹配 "zz"、"zzz" 或 "zzzz"。单独的右大括号不是特殊字符。如果省略第二个数字但逗号存在,则没有上限;如果第二个数字和逗号都被省略,则量词指定所需匹配的确切数量。因此 [aeiou]{3,} 匹配至少 3 个连续的元音,但可能匹配更多,而 \d{8} 匹配正好 8 位数字。

在 PHP 8.4.0 之前,出现在不允许使用量词的位置或与量词语法不匹配的左花括号将被视为文字字符。例如,{,6} 不是量词,而是四个字符的文字字符串。从 PHP 8.4.0 开始,PCRE 扩展捆绑了 PCRE2 10.44 版,允许使用诸如 \d{,8} 之类的模式,并将它们解释为 \d{0,8}。此外,从 PHP 8.4.0 开始,允许量词周围的空格字符,例如 \d{0 , 8}\d{ 0 , 8 }

允许使用量词 {0},这将导致表达式的行为如同不存在之前的项目和量词一样。

为方便起见(以及为了向后兼容性),三个最常用的量词具有单字符缩写

单字符量词
* 等效于 {0,}
+ 等效于 {1,}
? 等效于 {0,1}

可以通过跟随无法匹配任何字符的子模式和没有上限的量词来构造无限循环,例如:(a?)*

早期版本的 Perl 和 PCRE 过去会在编译时针对此类模式给出错误。但是,由于在某些情况下这可能很有用,因此现在接受此类模式,但是如果子模式的任何重复实际上都无法匹配任何字符,则会强制中断循环。

默认情况下,量词是“贪婪的”,也就是说,它们尽可能多地匹配(最多允许的次数),而不会导致模式的其余部分失败。这导致问题的经典示例是尝试匹配 C 程序中的注释。它们出现在 /* 和 */ 序列之间,并且在序列中可能出现单个 * 和 / 字符。尝试通过将模式 /\*.*\*/ 应用于字符串 /* first comment */ not comment /* second comment */ 来匹配 C 注释会失败,因为它由于 .* 项目的贪婪性而匹配整个字符串。

但是,如果量词后跟一个问号,则它变为“懒惰的”,而是匹配尽可能少的次数,因此模式 /\*.*?\*/ 对 C 注释执行正确的操作。各种量词的含义不会因此而改变,只是首选匹配的数量。不要将问号在此处的用法与其自身的量词用法混淆。因为它有两个用途,所以有时它可能会出现两次,就像在 \d??\d 中一样,它优先匹配一位数字,但如果这是其余模式匹配的唯一方法,则可以匹配两位数字。

如果设置了 PCRE_UNGREEDY 选项(Perl 中不可用的选项),则量词默认情况下不是贪婪的,但是可以通过在其后添加问号来使单个量词变为贪婪的。换句话说,它反转了默认行为。

后跟 + 的量词是“独占的”。它们会尽可能多地“吃掉”字符,并且不会返回来匹配模式的其余部分。因此 .*abc 匹配 "aabc",但 .*+abc 不会,因为 .*+ 会“吃掉”整个字符串。独占量词可用于加快处理速度。

当带括号的子模式用大于 1 的最小重复次数或有限的最大值进行量化时,编译后的模式所需的存储量会成比例地增加,这与最小值或最大值的大小成正比。

如果模式以 .* 或 .{0,} 开头,并且设置了 PCRE_DOTALL 选项(等效于 Perl 的 /s),从而允许 . 匹配换行符,则模式隐式地固定,因为无论后续的内容都会针对主题字符串中的每个字符位置进行尝试,因此在第一个位置之后,在任何位置重试整体匹配都没有意义。PCRE 将此类模式视为在其前面加上 \A。在已知主题字符串不包含换行符的情况下,当模式以 .* 开头时,设置 PCRE_DOTALL 以获得此优化是值得的,或者可以使用 ^ 来明确指示固定。

当捕获子模式重复时,捕获的值是匹配最终迭代的子字符串。例如,在 (tweedle[dume]{3}\s*)+ 匹配 "tweedledum tweedledee" 之后,捕获子字符串的值为 "tweedledee"。但是,如果存在嵌套的捕获子模式,则相应的捕获值可能已在之前的迭代中设置。例如,在 /(a|(b))+/ 匹配 "aba" 之后,第二个捕获子字符串的值为 "b"。

添加注释

用户贡献的注释

此页面没有用户贡献的注释。
To Top