在PHP教程的这一部分,我们介绍了PHP中的正则表达式。
$ php -v php -v PHP 8.1.2 (cli) (built: Aug 8 2022 07:28:23) (NTS) ...
我们使用PHP版本8.1.2。
正则表达式用于文本搜索和更高级的文本操作。正则表达式是内置工具,例如grep、sed、文本编辑器(例如vi、emacs)以及编程语言(例如Tcl、Perl和Python)。PHP也内置了对正则表达式的支持。
在PHP中,有两个正则表达式模块:POSIXRegex和PCRE。POSIX正则表达式已贬值。在本章中,我们将使用PCRE示例。PCRE代表Perl兼容正则表达式。
当我们使用正则表达式时需要两件事:Regex函数和模式。
模式是一个正则表达式,用于定义我们正在搜索或操作的文本。它由文本文字和元字符组成。模式位于两个定界符内。这些通常是//
、##
或@@
字符。它们通知正则表达式函数模式开始和结束的位置。
这是PCRE中使用的部分元字符列表。
. |
匹配任何单个字符。 |
* |
匹配前面的元素零次或多次。 |
[] |
括号表达式。匹配括号内的一个字符。 |
[^] |
匹配一个不包含在括号内的字符。 |
^ |
匹配字符串中的起始位置。 |
$ |
匹配字符串中的结束位置。 |
| |
交替运算符。 |
PHPPRCE函数
我们定义了一些PCRE正则表达式函数。它们都有一个preg前缀。
preg_split
-按正则表达式模式拆分字符串preg_match
-执行正则表达式匹配preg_replace
-通过正则表达式模式搜索和替换字符串preg_grep
-返回与正则表达式模式匹配的数组条目
接下来我们将为每个函数提供一个示例。
php> print_r(preg_split("@\s@", "Jane\tKate\nLucy Marion")); Array ( [0] => Jane [1] => Kate [2] => Lucy [3] => Marion )
我们有四个用空格分隔的名字。\s
是代表空格的字符类。preg_split
函数返回数组中的拆分字符串。
php> echo preg_match("#[a-z]#", "s"); 1
preg_match
函数查找’s’字符是否在字符类[a-z]
中。该类代表从a到z的所有字符。它返回1表示成功。
php> echo preg_replace("/Jane/","Beky","I saw Jane. Jane was beautiful."); I saw Beky. Beky was beautiful.
preg_replace
函数将所有出现的单词“Jane”替换为单词“Beky”。
php> print_r(preg_grep("#Jane#", ["Jane", "jane", "Joan", "JANE"])); Array ( [0] => Jane )
preg_grep
函数返回匹配给定模式的单词数组。在此示例中,数组中仅返回一个单词。这是因为默认情况下,搜索区分大小写。
php> print_r(preg_grep("#Jane#i", ["Jane", "jane", "Joan", "JANE"])); Array ( [0] => Jane [1] => jane [3] => JANE )
在这个例子中,我们执行不区分大小写的grep。我们将i
修饰符放在右分隔符之后。返回的数组现在有三个单词。
PHP正则表达式点元字符
.
(点)元字符代表文本中的任何单个字符。
<?php $words = [ "Seven", "even", "Maven", "Amen", "Leven" ]; $pattern = "/.even/"; foreach ($words as $word) { if (preg_match($pattern, $word)) { echo "$word matches the pattern\n"; } else { echo "$word does not match the pattern\n"; } }
在$words
数组中,我们有五个单词。
$pattern = "/.even/";
这里我们定义搜索模式。模式是一个字符串。正则表达式放在定界符内。分隔符是强制性的。在我们的例子中,我们使用正斜杠//
作为分隔符。请注意,如果需要,我们可以使用不同的定界符。点字符代表任何单个字符。
if (preg_match($pattern, $word)) { echo "$word matches the pattern\n"; } else { echo "$word does not match the pattern\n"; }
我们测试所有五个单词是否与模式匹配。
$ php single.php Seven matches the pattern even does not match the pattern Maven does not match the pattern Amen does not match the pattern Leven matches the pattern
Seven和Leven单词符合我们的搜索模式。
PHP正则表达式锚点
锚匹配给定文本中字符的位置。
在下一个示例中,我们将查看字符串是否位于句子的开头。
<?php $sentence1 = "Everywhere I look I see Jane"; $sentence2 = "Jane is the best thing that happened to me"; if (preg_match("/^Jane/", $sentence1)) { echo "Jane is at the beginning of the \$sentence1\n"; } else { echo "Jane is not at the beginning of the \$sentence1\n"; } if (preg_match("/^Jane/", $sentence2)) { echo "Jane is at the beginning of the \$sentence2\n"; } else { echo "Jane is not at the beginning of the \$sentence2\n"; }
我们有两个句子。模式是^Jane
。该模式检查’Jane’字符串是否位于文本的开头。
$ php anchors.php Jane is not at the beginning of the $sentence1 Jane is at the beginning of the $sentence2
php> echo preg_match("#Jane$#", "I love Jane"); 1 php> echo preg_match("#Jane$#", "Jane does not love me"); 0
Jane$
模式匹配以单词Jane结尾的字符串。
PHP正则表达式精确匹配
在以下示例中,我们展示了如何查找精确的单词匹配。
php> echo preg_match("/mother/", "mother"); 1 php> echo preg_match("/mother/", "motherboard"); 1 php> echo preg_match("/mother/", "motherland"); 1
mother
模式适合单词mother、motherboard和motherland。比如说,我们只想寻找精确的单词匹配。我们将使用上述锚点^
和$
字符。
php> echo preg_match("/^mother$/", "motherland"); 0 php> echo preg_match("/^mother$/", "Who is your mother?"); 0 php> echo preg_match("/^mother$/", "mother"); 1
使用锚字符,我们可以得到与模式完全匹配的单词。
PHP正则表达式量词
标记或组之后的量词指定允许前面的元素出现的频率。
? - 0 or 1 match * - 0 or more + - 1 or more {n} - exactly n {n,} - n or more {,n} - n or less (??) {n,m} - range n to m
以上是常用量词的列表。
问号?
表示前面有零个或一个元素。
<?php $words = [ "color", "colour", "comic", "colourful", "colored", "cosmos", "coloseum", "coloured", "colourful" ]; $pattern = "/colou?r/"; foreach ($words as $word) { if (preg_match($pattern, $word)) { echo "$word matches the pattern\n"; } else { echo "$word does not match the pattern\n"; } }
$words
数组中有四个九。
$pattern = "/colou?r/";
Color用于美式英语,color用于英式英语。此模式匹配两种情况。
$ php zeroorone.php color matches the pattern colour matches the pattern comic does not match the pattern colourful matches the pattern colored matches the pattern cosmos does not match the pattern coloseum does not match the pattern coloured matches the pattern colourful matches the pattern
这是zeroorone.php
脚本的输出。
*
元字符与前面的元素匹配零次或多次。
<?php $words = [ "Seven", "even", "Maven", "Amen", "Leven" ]; $pattern = "/.*even/"; foreach ($words as $word) { if (preg_match($pattern, $word)) { echo "$word matches the pattern\n"; } else { echo "$word does not match the pattern\n"; } }
在上面的脚本中,我们添加了*
元字符。.*
组合表示零个、一个或多个单个字符。
$ php zeroormore.php Seven matches the pattern even matches the pattern Maven does not match the pattern Amen does not match the pattern Leven matches the pattern
现在模式匹配三个词:Seven、even和Leven。
php> print_r(preg_grep("#o{2}#", ["gool", "root", "foot", "dog"])); Array ( [0] => gool [1] => root [2] => foot )
o{2}
模式匹配恰好包含两个“o”字符的字符串。
php> print_r(preg_grep("#^\d{2,4}$#", ["1", "12", "123", "1234", "12345"])); Array ( [1] => 12 [2] => 123 [3] => 1234 )
我们有这个^\d{2,4}$
模式。\d
是一个字符集;它代表数字。该模式匹配具有2、3或4位数字的数字。
PHP正则表达式替换
下一个例子解释了交替运算符|
。此运算符可以创建具有多种选择的正则表达式。
<?php $names = [ "Jane", "Thomas", "Robert", "Lucy", "Beky", "John", "Peter", "Andy" ]; $pattern = "/Jane|Beky|Robert/"; foreach ($names as $name) { if (preg_match($pattern, $name)) { echo "$name is my friend\n"; } else { echo "$name is not my friend\n"; } }
$names
数组中有八个名字。
$pattern = "/Jane|Beky|Robert/";
这是搜索模式。该模式查找“Jane”、“Beky”或“Robert”字符串。
$ php alternation.php Jane is my friend Thomas is not my friend Robert is my friend Lucy is not my friend Beky is my friend John is not my friend Peter is not my friend Andy is not my friend
这是脚本的输出。
PHP正则表达式子模式
我们可以使用方括号在模式中创建子模式。
php> echo preg_match("/book(worm)?$/", "bookworm"); 1 php> echo preg_match("/book(worm)?$/", "book"); 1 php> echo preg_match("/book(worm)?$/", "worm"); 0
我们有以下正则表达式模式:book(worm)?$
。(worm)
是一个子模式。这?字符跟在子模式之后,这意味着子模式可能在最终模式中出现0、1次。$
字符在这里用于字符串的精确结束匹配。如果没有它,像bookstore、bookmania这样的词也会匹配。
php> echo preg_match("/book(shelf|worm)?$/", "book"); 1 php> echo preg_match("/book(shelf|worm)?$/", "bookshelf"); 1 php> echo preg_match("/book(shelf|worm)?$/", "bookworm"); 1 php> echo preg_match("/book(shelf|worm)?$/", "bookstore"); 0
子模式经常交替使用。(shelf|worm)
子模式可以创建多个单词组合。
PHP正则表达式字符类
我们可以用方括号将字符组合成字符类。字符类匹配括号中指定的任何字符。
<?php $words = [ "sit", "MIT", "fit", "fat", "lot" ]; $pattern = "/[fs]it/"; foreach ($words as $word) { if (preg_match($pattern, $word)) { echo "$word matches the pattern\n"; } else { echo "$word does not match the pattern\n"; } }
我们定义了一个包含两个字符的字符集。
$pattern = "/[fs]it/";
这是我们的模式。[fs]
是字符类。请注意,我们一次只处理一个字符。我们要么考虑f,要么考虑s,但不能同时考虑。
$ php characterclass.php sit matches the pattern MIT does not match the pattern fit matches the pattern fat does not match the pattern lot does not match the pattern
这是脚本的结果。
我们还可以为字符类使用速记元字符。\w
代表字母数字字符,\d
代表数字,\s
空白字符。
<?php $words = [ "Prague", "111978", "terry2", "mitt##" ]; $pattern = "/\w{6}/"; foreach ($words as $word) { if (preg_match($pattern, $word)) { echo "$word matches the pattern\n"; } else { echo "$word does not match the pattern\n"; } }
在上面的脚本中,我们测试了由字母数字字符组成的单词。\w{6}
代表六个字母数字字符。只有单词mitt##
不匹配,因为它包含非字母数字字符。
php> echo preg_match("#[^a-z]{3}#", "ABC"); 1
#[^a-z]{3}#
模式代表三个不在a-z类中的字符。“ABC”字符符合条件。
php> print_r(preg_grep("#\d{2,4}#", [ "32", "234", "2345", "3d3", "2"])); Array ( [0] => 32 [1] => 234 [2] => 2345 )
在上面的示例中,我们有一个匹配2、3和4位数字的模式。
PHP正则表达式提取匹配项
preg_match
采用可选的第三个参数。如果提供,它会填充搜索结果。该变量是一个数组,其第一个元素包含与完整模式匹配的文本,第二个元素包含第一个捕获的带括号的子模式,依此类推。
<?php $times = [ "10:10:22", "23:23:11", "09:06:56" ]; $pattern = "/(\d\d):(\d\d):(\d\d)/"; foreach ($times as $time) { $r = preg_match($pattern, $time, $match); if ($r) { echo "The $match[0] is split into:\n"; echo "Hour: $match[1]\n"; echo "Minute: $match[2]\n"; echo "Second: $match[3]\n"; } }
在示例中,我们提取了部分时间字符串。
$times = [ "10:10:22", "23:23:11", "09:06:56" ];
我们在英语语言环境中有三个时间字符串。
$pattern = "/(\d\d):(\d\d):(\d\d)/";
该模式使用方括号分为三个子模式。我们想具体指代每个部分。
$r = preg_match($pattern, $time, $match);
我们将第三个参数传递给preg_match
函数。在匹配的情况下,它包含匹配字符串的文本部分。
if ($r) { echo "The $match[0] is split into:\n"; echo "Hour: $match[1]\n"; echo "Minute: $match[2]\n"; echo "Second: $match[3]\n"; }
$match[0]
包含与完整模式匹配的文本,$match[1]
包含与第一个子模式匹配的文本,$match[2]
第二个,$match[3]
第三个。
$ php extract_matches.php The 10:10:22 is split into: Hour: 10 Minute: 10 Second: 22 The 23:23:11 is split into: Hour: 23 Minute: 23 Second: 11 The 09:06:56 is split into: Hour: 09 Minute: 06 Second: 56
这是示例的输出。
PHP正则表达式电子邮件示例
接下来有一个实际的例子。我们创建了一个正则表达式模式来检查电子邮件地址。
<?php $emails = [ "luke@gmail.com", "andy@yahoocom", "34234sdfa#2345", "f344@gmail.com"]; # regular expression for emails $pattern = "/^[a-zA-Z0-9._-]+@[a-zA-Z0-9-]+\.[a-zA-Z.]{2,18}$/"; foreach ($emails as $email) { if (preg_match($pattern, $email)) { echo "$email matches \n"; } else { echo "$email does not match\n"; } } >?
请注意,此示例仅提供一种解决方案。它不一定是最好的。
$pattern = "/^[a-zA-Z0-9._-]+@[a-zA-Z0-9-]+\.[a-zA-Z.]{2,18}$/";
这是模式。第一个^
和最后一个$
字符在这里用于获得精确的模式匹配。模式前后不允许有任何字符。邮件分为五个部分。第一部分是本地部分。这通常是公司名称、个人名称或昵称。[a-zA-Z0-9._-]+
列出了所有可能的字符,我们可以在本地部分使用。它们可以使用一次或多次。第二部分是文字@
字符。第三部分是领域部分。它通常是电子邮件提供商的域名,例如yahoo或gmail。[a-zA-Z0-9-]+
是一个字符集,提供了可以在域名中使用的所有字符。+
量词使用这些字符中的一个或多个。第四部分是点字符。它前面是转义字符(\)。这是因为点字符是元字符,具有特殊含义。通过转义它,我们得到一个字面意义的点。最后一部分是顶级域。模式如下:[a-zA-Z.]{2,18}
顶级域可以包含2到18个字符,例如sk、net、info、travel、cleaning、travelinsurance。最大长度可以是63个字符,但现在大多数域都短于18个字符。还有一个点字符。这是因为一些顶级域有两个部分;例如co.uk。
$ php emails.php luke@gmail.com matches andy@yahoocom does not match 34234sdfa#2345 does not match f344@gmail.com matches
这是emails.php
示例的输出。
回顾
最后,我们提供了对正则表达式模式的快速回顾。
Jane the 'Jane' string ^Jane 'Jane' at the start of a string Jane$ 'Jane' at the end of a string ^Jane$ exact match of the string 'Jane' [abc] a, b, or c [a-z] any lowercase letter [^A-Z] any character that is not a uppercase letter (Jane|Becky) Matches either 'Jane' or 'Becky' [a-z]+ one or more lowercase letters ^[98]?$ digits 9, 8 or empty string ([wx])([yz]) wy, wz, xy, or xz [0-9] any digit [^A-Za-z0-9] any symbol (not a number or a letter)
在本章中,我们介绍了PHP中的正则表达式。
列出所有PHP教程。