1.正则表达式修正符
++在 PHP 中,正则表达式中的修正符(modifier)可以改变模式的行为++,使得其功能更加灵活。
1. m
修正符(多行模式)
- 作用 :在多行模式下,
^
和$
元字符除了匹配整个字符串的开头和结尾外,还可以匹配每一行的开头和结尾。 - 举例 :
"Hello\nWorld"
,当使用/^World/m
时,^
会匹配"World"
这一行的开头,而不仅仅匹配整个字符串的开头。
2. s
修正符(单行模式)
- 作用 :使
.
(点号)可以匹配所有字符,包括换行符(\n
) 。如果不加此修正符,.
默认匹配除换行符外的所有字符。 - 举例 :假设有字符串
"Hello\nWorld"
,使用/Hello.World/s
时,.
可以匹配换行符,因此该正则表达式可以成功匹配整个字符串。
3. x
修正符(忽略模式中的空白字符)
- 作用 :开启"扩展模式",忽略模式中的空白字符 (除非在字符类
[]
内或被反斜杠转义),还会忽略未转义的#
后的内容直到该行结束。通常用于编写更易读的正则表达式。 - 举例 :正则表达式
/a b c/x
实际上会被解析为/abc/
,即空格被忽略。
4. e
修正符(已废弃,自 PHP 5.5.0 起)
- 作用 :该修正符曾用于
preg_replace()
函数,允许在替换时对替换字符串中的反向引用进行 PHP 代码的执行。由于存在安全性问题,该修正符已被弃用。 - 替代方案 :可以使用
preg_replace_callback()
来实现类似功能。++(后文介绍)++
5. i 修正符
- 作用: 匹配过程中不区分大小写。
举例:/abc/i
可以匹配"AbC"
6. 非贪婪匹配(使用 ?
实现)
- 贪婪匹配 :正则表达式中的
*
、+
和?
默认是贪婪的,即它们会匹配尽可能多的字符。 - 非贪婪匹配 :在贪婪量词后加
?
,可以使匹配变为非贪婪(也称为"最小匹配"),即匹配尽可能少的字符。 - 举例 :
- 贪婪匹配:
/a.*b/
会匹配从第一个a
开始到最后一个b
之间的所有内容。 - 非贪婪匹配:
/a.*?b/
只匹配第一个a
和第一个b
之间的最少字符。
- 贪婪匹配:
总结
m
:多行匹配,^
和$
可以匹配每行的开头和结尾。s
:单行模式,.
可以匹配包括换行符在内的所有字符。x
:忽略正则中的空白字符,并允许使用注释。e
:在替换时允许执行 PHP 代码,现已弃用。?
:与*
、+
搭配使用可以实现非贪婪匹配。
2.贪婪匹配与非贪婪匹配
在正则表达式中,贪婪匹配 和 非贪婪匹配 是两个重要的概念,++它们决定了匹配操作在处理多个可能的匹配项时的行为。++
1. 贪婪匹配
贪婪匹配(Greedy Matching)是正则表达式的默认行为,即在匹配过程中,量词如 *
, +
和 {n,}
会尝试匹配尽可能多的字符。它们会从最早出现的匹配点开始,然后继续匹配更多字符,直到满足整个模式或者没有更多可以匹配的字符。
- 模式 :
/a.*b/
- 含义 :
a
:匹配字符a
。.*
:匹配任意字符(除了换行符),匹配尽可能多的字符。b
:匹配字符b
。
- 贪婪行为 :
.*
尽可能多地匹配字符,直到遇到最后一个可能的b
。 - 例子 :
- 字符串:
"a123b456b"
- 匹配结果:
"
a123b456b"
- 字符串:
在贪婪匹配中,.*
会从第一个 a
开始,匹配尽可能多的字符,直到遇到最后一个 b
。因此,它匹配整个 "a123b456b"
。
2. 非贪婪匹配
非贪婪匹配(Lazy Matching),也称为"最小匹配",是通过在量词后面加上 ?
来实现的。非贪婪匹配的行为是尽可能少地匹配字符,在满足整个模式的前提下只匹配最少的字符。
- 模式 :
/a.*?b/
- 非贪婪行为 :
.*?
尽可能少地匹配字符,直到遇到第一个b
就停止。 - 例子 :
- 字符串:
"a123b456b"
- 匹配结果:
"
a123b"
- 字符串:
在非贪婪匹配中,.*?
从第一个 a
开始,匹配尽可能少的字符,直到遇到第一个 b
就停止。因此,它只匹配 "a123b"
。
图示化理解:
-
贪婪匹配:
字符串
a123b456b
-> 贪婪正则/a.*b/
-> 匹配到整个a123b456b
。 -
非贪婪匹配:
字符串
a123b456b
-> 非贪婪正则/a.*?b/
-> 匹配到a123b
(尽量少匹配)。
总结
- 贪婪匹配 :
/a.*b/
尽可能多地匹配,从第一个a
开始匹配到最后一个b
。- 非贪婪匹配 :
/a.*?b/
尽可能少地匹配,从第一个a
开始匹配到第一个b
。
3.(?i)
修正符的解释
在 PHP 的正则表达式中,(?i)
是一个**++内部修正符,用于指定在正则表达式的某个部分中忽略大小写进行匹配++** 。它等同于我们在正则表达式外部使用修正符 i
,只是 (?i)
修正符的效果可以局部应用于特定的子模式。
1. 用法说明
(?i)
:内部修正符,表示该部分不区分大小写。- 区别 :如果使用外部的
i
修正符,则整个模式都不区分大小写;但(?i)
修正符只影响它所在的子模式。
2. 示例
- 外部修正符:
/abc/i
- 模式
/abc/i
中的i
修正符表示整个正则表达式不区分大小写。 - 它将匹配
"abc"
、"ABC"
、"aBc"
等所有大小写组合。
- 模式
- 内部修正符:
/a(?i)bc/
- 模式
/a(?i)bc/
中的(?i)
只对其后面的bc
起作用。 - 它将匹配
"abc"
、"aBC"
,但不会匹配"ABC"
或"Abc"
,因为a
仍然区分大小写。
- 模式
3. 结合其它修正符
与外部修正符相似,内部修正符还包括:
x
:忽略正则表达式中的空白字符。m
:多行模式,使^
和$
匹配行的开头和结尾,而不仅是字符串的开头和结尾。s
:单行模式,使.
匹配包括换行符在内的所有字符。U
:非贪婪模式,默认使用非贪婪匹配。
4.后向引用(Backreference)
后向引用是一种可以在正则表达式中引用之前捕获的子模式的方法。通过在模式中添加圆括号 ()
来定义捕获组,PHP 会自动为每个捕获的子模式分配一个编号,++这个编号从 1
开始。在后续的模式中,可以使用反斜杠 \n
(其中 n
是捕获组的编号)来引用之前的匹配。++
1. 示例
-
模式:
/(a)(b)(c)/
- 这将捕获
a
、b
、c
,它们分别存储在捕获组 1、2、3 中。 - 可以使用后向引用来重新引用这些捕获的部分,例如
/\1\2\3/
将匹配abc
。
- 这将捕获
-
示例:
- 正则表达式
/(a)(b)\1\2/
将匹配类似ab
后跟ab
的字符串。 - 在字符串
"abxab"
中,模式/(a)(b)\1\2/
将匹配"abab"
。
- 正则表达式
2. 非捕获组
有时我们只想匹配某些内容,但不希望将其存储在捕获组中。这时可以使用非捕获元字符 (?:)
来忽略捕获。
- 示例:
(?:abc)
会匹配"abc"
,但不会将其存储为捕获组,因此不会占用编号。
其他的非捕获组符号包括:
(?=...)
:正向肯定断言,匹配在指定位置后必须跟随的内容。(?!...)
:正向否定断言,匹配在指定位置后不能跟随的内容。
总结
(?i)
:内部修正符,指定模式中的某部分不区分大小写。- 后向引用:使用
()
捕获匹配内容,并通过\n
进行引用。- 非捕获组:使用
(?:)
或断言符号来匹配但不保存相关内容。
5.正则表达式中的断言
++断言用于定义在某个位置前后必须或不能出现的内容,称为零宽断言++(zero-width assertions),因为它们只检查条件,而不会消耗字符。
1. 正向肯定断言 :(?=...)
正向肯定断言表示匹配某位置后面必须跟随的内容,但这些内容本身并不会成为匹配结果的一部分。
- 格式 :
(?=...)
- 作用: 确保在当前位置之后,有满足断言条件的字符出现。
例子:
-
正则表达式:
/\d(?=\D)/
- 含义:匹配一个数字(
\d
),条件是它后面跟随一个非数字字符(\D
),但不包含这个非数字字符在匹配结果中。 - 示例字符串:
"123a4b"
- 匹配结果:
["3", "4"]
在
"123a4b"
中,"3"
后跟的是字母"a"
,"4"
后跟的是字母"b"
,所以它们符合正向肯定断言的条件。 - 含义:匹配一个数字(
2. 正向否定断言 :(?!...)
正向否定断言表示匹配某位置后面不能跟随的内容,即当前位置后如果有符合条件的字符出现,匹配将失败。
- 格式 :
(?!...)
- 作用: 确保在当前位置之后,不能有满足断言条件的字符。
例子:
-
正则表达式:
/\d(?!\d)/
- 含义:匹配一个数字,条件是它后面不能跟随另一个数字(即确保当前匹配的是最后一个连续数字)。
- 示例字符串:
"123a456b"
- 匹配结果:
["3", "6"]
在
"123a456b"
中,"3"
后面不是数字,而是字母"a"
,"6"
后面也不是数字,而是字母"b"
,因此它们符合正向否定断言的条件。
总结
正向肯定断言
(?=...)
: 匹配某个位置后必须跟随的内容,但不包括该内容在最终匹配中。例如,匹配某个字符后跟随特定字符但不包含它。正向否定断言
(?!...)
: 匹配某个位置后不能跟随的内容。例如,匹配某个字符,条件是它后面不允许跟随特定字符。