PHP正则表达式Preg函数接口详解
1. 前瞻和模式修饰符基础
- 前瞻限制 :后向引用(Lookbehind)仅限于匹配固定长度文本的子表达式,不过允许顶级的不同固定长度的可选分支。
- x模式修饰符 :x模式修饰符(自由间距和注释)仅识别ASCII空格,不识别Unicode中的其他空格。
2. Preg函数接口概述
PHP的正则表达式引擎接口是纯过程式的,由以下六个主要函数提供:
| 函数 | 用途 |
| — | — |
| pregRmatch | 检查正则表达式是否能在字符串中匹配,并从字符串中提取数据 |
| pregRmatchRall | 从字符串中提取数据 |
| pregRreplace | 在字符串副本中替换匹配的文本 |
| pregRreplaceRcallback | 为字符串中每个正则表达式匹配项调用一个函数 |
| pregRsplit | 将字符串分割成子字符串数组 |
| pregRgrep | 从数组中筛选出匹配或不匹配正则表达式的元素 |
| pregRquote | 转义字符串中的正则表达式元字符 |
此外,还有一些辅助函数:
- regRmatch:pregRmatch的非参与括号感知版本。
- pregRregexRtoRpattern:从正则表达式字符串创建preg模式字符串。
- pregRpatternRerror:检查preg模式字符串的语法错误。
- pregRregexRerror:检查正则表达式字符串的语法错误。
这些函数的实际行为受提供的参数类型和数量、函数标志以及正则表达式使用的模式修饰符的影响。下面是一些示例,让我们感受一下正则表达式在PHP中的样子和处理方式:
// 检查HTML标签是否为<table>标签
if (pregRmatch('/^<table\b/i', $tag))
print "tag is a table tag\n";
// 检查文本是否为整数
if (pregRmatch('/^-?\d+$/',$userRinput))
print "user input is an integer\n";
// 从字符串中提取HTML标题
if (pregRmatch('{<title>(.+?)</title>}si', $html, $matches))
print "page title: $matches[1]\n";
// 将字符串中的数字视为华氏温度值并替换为摄氏温度值
$metric = pregRreplace('/(-?\d+(?:\.\d+)?)/e',
'floor(($1-32)*5/9 + 0.5)',
$string);
// 从充满简单逗号分隔值的字符串创建值数组
$valuesRarray = pregRsplit('!\s*,\s*!', $commaRseparatedRvalues);
3. “模式”参数
任何preg函数的第一个参数都是模式参数,它是由一对定界符包裹的正则表达式,可能后面还跟着模式修饰符。例如,在
pregRmatch('/^<table\b/i', $tag)
中,模式参数是
'/^<table\b/i'
,它是由一对斜杠(定界符)包裹的正则表达式
<table\b
,后面跟着i(不区分大小写匹配)模式修饰符。
4. PHP单引号字符串
由于正则表达式倾向于包含反斜杠,在提供这些模式参数作为字符串字面量时,使用PHP的单引号字符串最为方便。PHP单引号字符串只有两个字符串元序列:
\'
和
\\
,分别用于在字符串值中包含单引号和反斜杠。
例如,要匹配Windows磁盘的根路径,如
C:\
,正则表达式是
^[A-Z]:\\$
,在单引号字符串字面量中表示为
'^[A-Z]:\\\\$'
。
以下是一些示例,展示了单引号字符串中反斜杠的处理:
print '/^.+\/';
// 输出: /^.+\/
print '/^.+\\/';
// 输出: /^.+\/
print '/^.+\\\/';
// 输出: /^.+\\/
print '/^.+\\\\/';
// 输出: /^.+\\/
5. 定界符
preg引擎要求在正则表达式周围使用定界符,因为设计者希望提供更像Perl的外观,特别是在模式修饰符方面。通常使用斜杠作为定界符,但也可以使用任何非字母数字、非空格的ASCII字符(除反斜杠外)。常见的定界符对有
/
、
!
和
#
。
如果第一个定界符是“开放”标点符号,如
{
、
(
、
<
、
[
,则关闭定界符变为相应的匹配关闭标点符号,如
}
、
)
、
>
、
]
。使用这些“配对”定界符时,定界符可以嵌套,但为了清晰起见,建议使用简单的形式,如
/(\d+)/
。
定界符可以在模式参数字符串的正则表达式部分进行转义,例如
/<B>(.+?)<\/B>/i
是允许的,但使用不同的定界符可能会使代码更清晰,如
!<B>(.+?)</B>!i
或
{<B>(.+?)</B>}i
。
6. 模式修饰符
模式修饰符可以放在关闭定界符之后,或者在某些情况下,放在正则表达式内部,以修改模式使用的某些方面。以下是所有允许的模式修饰符的总结:
| 修饰符 | 内联形式 | 描述 |
| — | — | — |
| i |
(?i)
| 匹配时忽略字母大小写 |
| m |
(?m)
| 增强行锚点匹配模式 |
| s |
(?s)
| 点匹配所有字符的匹配模式 |
| x |
(?x)
| 自由间距和注释正则表达式模式 |
| u | | 将正则表达式和目标字符串视为UTF - 8编码 |
| X |
(?X)
| 启用PCRE“额外功能” |
| e | | 将替换内容作为PHP代码执行(仅用于pregRreplace) |
| S | | 调用PCRE的“研究”优化尝试 |
| U |
(?U)
| 交换
+
和
+?
等的贪婪性 |
| A | | 将整个匹配锚定到尝试的初始起始位置 |
| D | |
$
仅在字符串末尾匹配,不在字符串末尾换行符之前匹配(如果使用m模式修饰符则忽略) |
7. 模式修饰符的使用方式
-
正则表达式内部
:模式修饰符嵌入正则表达式时,可以独立出现以打开或关闭某个功能,如
(?i)打开不区分大小写匹配,(?-i)关闭。它们的作用范围持续到包含它们的括号组结束,或者到正则表达式结束。也可以用作模式修改范围,如(?i:...)在该范围内打开不区分大小写匹配,(?-sm:...)在该范围内关闭s和m模式。 -
正则表达式外部
:修饰符可以在最终定界符之后以任意顺序组合,例如
si可以同时启用不区分大小写和点匹配所有字符的模式。
8. PHP特定的模式修饰符
- u修饰符 :告诉preg正则表达式引擎将正则表达式和主题字符串的字节视为UTF - 8编码。使用此修饰符不会改变字节,只是改变引擎对它们的处理方式。默认情况下,preg引擎将传递给它的数据视为当前8位区域设置。如果知道数据是UTF - 8编码的,就使用此修饰符;否则,不要使用。
-
X修饰符
:打开PCRE“额外功能”,当前的效果是当反斜杠用于非已知元序列的情况时生成错误。例如,默认情况下,
\k对PCRE没有特殊意义,会被视为k,但使用X修饰符会导致“未识别的字符跟随\”致命错误。 - S修饰符 :调用PCRE的“研究”功能,对正则表达式进行预分析,在某些情况下可以显著加快匹配尝试。
-
其他修饰符
:A、D和U修饰符比较深奥,很少使用。A修饰符将匹配锚定到匹配尝试开始的位置;D修饰符将每个
$转换为\z;U修饰符交换元字符的贪婪性。
9. “未知修饰符”错误
在编写程序时,有时会突然出现“未知修饰符”错误,这通常是因为在创建模式参数时忘记为正则表达式添加定界符。例如:
pregRmatch('<(\w+)([^>]+)>', $html);
这里,pregRmatch会将
<
视为打开定界符,导致后续代码被错误解释。正确的做法是添加定界符,如
pregRmatch('/<(\w+)(.+?)>/', $html);
。
10. pregRmatch函数详解
-
用法
:
pregRmatch(pattern, subject [, matches [, flags [, offset ]]]) -
参数总结
:
- pattern :模式参数,即由定界符包裹的正则表达式,可选地带有修饰符。
- subject :要搜索的目标字符串。
- matches :可选变量,用于接收匹配数据。
-
flags
:可选标志,影响函数整体行为,只允许一个标志
PREG_OFFSET_CAPTURE。 - offset :可选的从零开始的偏移量,指定在目标字符串中开始匹配尝试的位置。
- 返回值 :如果找到匹配项,则返回真值;否则返回假值。
- 简单示例 :
if (pregRmatch('/\.(jpe?g|png|gif|bmp)$/i', $url)) {
// URL似乎是图像
}
if (pregRmatch('{^https?://}', $uri)) {
// URI是http或https
}
if (pregRmatch('/\b MSIE \b/x', $_SERVER['HTTP_USER_AGENT'])) {
// 浏览器是IE
}
-
捕获匹配数据
:pregRmatch的第三个可选参数是一个变量,用于接收匹配结果的信息。成功匹配后,
$matches数组的设置如下:-
$matches[0]是正则表达式匹配的整个文本。 -
$matches[1]是第一个捕获括号匹配的文本。 -
$matches[2]是第二个捕获括号匹配的文本,依此类推。
-
例如:
// 从完整路径中分离文件名
if (pregRmatch('{ / ([^/]+) $}x', $WholePath, $matches))
$FileName = $matches[1];
需要注意的是,只有在pregRmatch返回真值后,才能安全使用
$matches
变量。如果匹配不成功或出现错误(如错误的模式或函数标志),则返回假值。有些错误会将
$matches
清空为一个空数组,而有些错误会保留其之前的值,因此不能仅仅因为
$matches
不为空就认为它是有效的。
- 更复杂的示例 :
// 从URL中提取协议、主机名和端口号
if (pregRmatch('{^(\w+):\/\/([^\/:]+)(?::(\d+))?}', $url, $matches)) {
$protocol = $matches[1];
$hostname = $matches[2];
$port = isset($matches[3]) ? $matches[3] : ($protocol == 'http' ? 80 : 443);
echo "Protocol: $protocol\n";
echo "Hostname: $hostname\n";
echo "Port: $port\n";
}
-
尾随“非参与”元素的处理
:一组不参与最终匹配的括号在对应的
$matches元素中会产生一个空字符串。需要注意的是,尾随的非参与捕获元素甚至不会包含在$matches中。例如,如果(\d+)参与了匹配,$matches[3]会得到一个数字;如果它没有参与,$matches[3]在数组中甚至不存在。 - 命名捕获 :使用命名捕获可以使代码更具自文档性。例如:
if (pregRmatch('{^(?P<protocol>\w+):\/\/(?P<hostname>[^\/:]+)(?::(?P<port>\d+))?}', $url, $matches)) {
$protocol = $matches['protocol'];
$hostname = $matches['hostname'];
$port = isset($matches['port']) ? $matches['port'] : ($protocol == 'http' ? 80 : 443);
echo "Protocol: $protocol\n";
echo "Hostname: $hostname\n";
echo "Port: $port\n";
}
使用命名捕获时,编号捕获仍然会插入到
$matches
中,这会导致一定的重复,但这是为了方便和清晰而付出的代价。为了清晰起见,除了
$matches[0]
作为整体匹配外,不建议同时使用命名和数字引用
$matches
的元素。
11. pregRmatchAll函数
-
用法
:
pregRmatchAll(pattern, subject, matches [, flags [, offset ]]) -
参数总结
:
-
pattern
:模式参数,同
pregRmatch,是带定界符和可选修饰符的正则表达式。 - subject :目标字符串,即要进行搜索的字符串。
- matches :用于接收所有匹配结果的数组。
-
flags
:可选标志,有多种取值,如
PREG_PATTERN_ORDER(默认,按模式中捕获组的顺序返回结果)、PREG_SET_ORDER(按每个匹配项的顺序返回结果)等。 - offset :可选的从零开始的偏移量,指定在目标字符串中开始匹配尝试的位置。
-
pattern
:模式参数,同
-
返回值
:返回匹配的次数,如果发生错误则返回
false。 - 示例 :
$html = '<p>First paragraph</p><p>Second paragraph</p>';
if (pregRmatchAll('{<p>(.*?)</p>}i', $html, $matches, PREG_PATTERN_ORDER)) {
foreach ($matches[1] as $paragraph) {
echo $paragraph . "\n";
}
}
在这个示例中,
pregRmatchAll
会找出所有的
<p>
标签内的内容,并存储在
$matches
数组中。由于使用了
PREG_PATTERN_ORDER
标志,
$matches[1]
包含了所有捕获组匹配的内容。
12. pregRreplace函数
-
用法
:
pregRreplace(pattern, replacement, subject [, limit [, count ]]) -
参数总结
:
- pattern :模式参数,正则表达式。
-
replacement
:替换字符串或数组,如果使用
e修饰符,会将其作为PHP代码执行。 - subject :目标字符串,要进行替换操作的字符串。
-
limit
:可选参数,指定最大替换次数,默认值为
-1表示无限制。 - count :可选参数,用于接收实际发生替换的次数。
-
返回值
:返回替换后的字符串,如果
subject是数组,则返回替换后的数组。 - 示例 :
$text = 'The quick brown fox jumps over the lazy dog.';
$newText = pregRreplace('/fox/', 'cat', $text);
echo $newText;
在这个示例中,
pregRreplace
将字符串中的
fox
替换为
cat
。
如果使用
e
修饰符,可以执行PHP代码进行替换:
$string = 'The price is $10, $20, $30.';
$newString = pregRreplace('/\$(\d+)/e', '($1 * 1.1)', $string);
echo $newString;
这里将字符串中的价格增加了10%。
13. pregRreplaceCallback函数
-
用法
:
pregRreplaceCallback(pattern, callback, subject [, limit [, count ]]) -
参数总结
:
- pattern :模式参数,正则表达式。
- callback :回调函数,用于处理每个匹配项。
- subject :目标字符串。
- limit :可选参数,最大替换次数。
- count :可选参数,接收实际替换次数。
- 返回值 :返回替换后的字符串或数组。
- 示例 :
$string = 'The price is $10, $20, $30.';
$newString = pregRreplaceCallback('/\$(\d+)/', function($matches) {
return '$' . ($matches[1] * 1.1);
}, $string);
echo $newString;
在这个示例中,使用回调函数将每个匹配到的价格增加了10%。
14. pregRsplit函数
-
用法
:
pregRsplit(pattern, subject [, limit [, flags ]]) -
参数总结
:
- pattern :模式参数,用于分割字符串的正则表达式。
- subject :目标字符串。
- limit :可选参数,指定分割后的最大元素数。
-
flags
:可选标志,如
PREG_SPLIT_NO_EMPTY(忽略空元素)等。
- 返回值 :返回分割后的数组。
- 示例 :
$commaSeparated = 'apple,banana,orange';
$array = pregRsplit('/,\s*/', $commaSeparated);
print_r($array);
这个示例将逗号分隔的字符串分割成数组。
15. pregRgrep函数
-
用法
:
pregRgrep(pattern, input [, invert ]) -
参数总结
:
- pattern :模式参数,正则表达式。
- input :输入数组,要进行筛选的数组。
-
invert
:可选参数,布尔值,如果为
true,则返回不匹配的元素。
- 返回值 :返回匹配或不匹配的元素组成的数组。
- 示例 :
$array = ['apple', 'banana', 'cherry'];
$matched = pregRgrep('/^a/', $array);
print_r($matched);
这个示例返回以字母
a
开头的元素组成的数组。
16. pregRquote函数
-
用法
:
pregRquote(str [, delimiter ]) -
参数总结
:
- str :要进行转义的字符串。
- delimiter :可选参数,指定定界符,会对其进行转义。
- 返回值 :返回转义后的字符串。
- 示例 :
$string = 'Hello. World!';
$escaped = pregRquote($string, '/');
echo $escaped;
这个示例将字符串中的正则表达式元字符进行了转义。
17. 正则表达式使用流程总结
下面是一个使用PHP正则表达式的基本流程图:
graph TD;
A[定义正则表达式模式] --> B[选择合适的preg函数];
B --> C[设置函数参数];
C --> D[执行函数];
D --> E{是否匹配成功};
E -- 是 --> F[处理匹配结果];
E -- 否 --> G[处理未匹配情况];
18. 注意事项和最佳实践
- 定界符和模式修饰符 :使用合适的定界符和模式修饰符,避免“未知修饰符”错误。在编写正则表达式时,要仔细检查定界符是否正确添加。
- 单引号字符串 :优先使用单引号字符串来表示正则表达式,减少反斜杠转义的复杂性。
- 错误处理 :在使用正则表达式函数时,要考虑错误情况,如无效的模式或函数标志。可以通过检查函数的返回值来判断是否发生错误。
-
性能优化
:对于复杂的正则表达式,可以使用
S模式修饰符调用PCRE的“研究”功能进行预分析,提高匹配效率。
通过以上对PHP正则表达式Preg函数接口的详细介绍,我们可以看到这些函数提供了强大而灵活的字符串处理能力。无论是简单的匹配、替换,还是复杂的字符串分割和筛选,都可以通过合理使用这些函数和正则表达式来实现。在实际开发中,要根据具体需求选择合适的函数和模式修饰符,并注意错误处理和性能优化,以确保代码的正确性和高效性。
超级会员免费看

360

被折叠的 条评论
为什么被折叠?



