正则表达式语法
尽管 POSIX 和 PCRE 实现在对某些特性和字符类的支持方面有所不同,但它们的语法是相同的。每个正则表达式都是由一个或多个字符、特殊字符(有时也称为元字符)、字符类和字符组构成的。
POSIX 和 PCRE 使用相同的通配符 —— 在 regex 中以通配符来表示 “此处可为任意内容”。通配符字符为一个英文句号或点(.)。若要查找英文句号或点,可使用转义字符 \: \.。下文中所讨论的其他特殊字符也是如此,例如行锚(line anchor)和限定符。如果一个字符在正则表达式中有特殊含义,那么必须通过转义才能表达其原本的文字含义。
行锚 是特殊的元字符,与一行的开头和结尾相匹配,但不会捕获任何文本(参见表 1)。例如,如果某一行以字母 a 开头,那么表达式 ^a 中的行锚不会捕获字母 a,而是匹配行的开头。
| 锚 | 描述 |
|---|---|
^ |
匹配一行的开头 |
$ |
匹配一行的结尾 |
限定符 应用于紧接于其前的表达式(参见表 2)。使用限定符,您可以指定在一次搜索中查找到一个表达式的次数。例如,表达式 a+ 将一次或多次地查找到字母 a。
| 限定符 | 描述 |
|---|---|
? |
限定符之前的表达式可被查找到 0 次或 1 次 |
+ |
限定符之前的表达式可被查找到 1 次或多次 |
* |
限定符之前的表达式可被查找到任意次(含 0 次) |
{n} |
限定符之前的表达式仅可被查找到 n 次 |
{n,m} |
限定符之前的表达式可被查找到 n 次到 m 次之间 |
在 regex 中,捕获文本并在替换和搜索操作中引用该文本是一项非常有用的特性(参见表 3)。通过使用捕获功能,您可以执行搜索,来查找重复的单词和闭合的 HTML 及 XML 标记。如果您在替换时使用了捕获功能,那么可以将找回的文本置入替换字符串内。后面将给出一个示例,展示如何以超链接替换电子邮件地址。
| 字符类 | 描述 |
|---|---|
() |
分组字符,并能够捕获文本 |
POSIX 正则表达式遵循一些使其可为许多 regex 实现所用的标准(参见表 4)。例如,如果您正在编写一条 POSIX 正则表达式,您可以在 PHP 中使用它、可以通过 grep 命令使用它,也可以通过许多支持正则表达式的编辑器使用它。
| 字符 | 描述 |
|---|---|
[:alpha:] |
匹配包含字母与数字的字符 |
[:digit:] |
匹配任意数字 |
[:space:] |
匹配任意空白 |
POSIX 匹配
有两个使用 POSIX 正则表达式搜索字符串的函数,即 ereg() 和 eregi()。
ereg() 方法为特定正则表达式搜索字符串。如果未找到任何匹配项,则返回 0,因此您可以给出如下测试:
|
正则表达式 [-[:digit:]]{12} 查找 12 个为数字或连字符的字符。就处理电话号码而言,这有些粗略,您也可将其改写成这样的形式:^[0-9]{3}-[0-9]{3}-[0-9]{4}$。(在 regex 中,[0-9] 和 [:digit:] 实际上是完全相同的,您可能更愿意使用 [0-9] 的形式,因为它更短些。)这种作为替代方案的表达式显然更为精确。它会查找行的开头(^),后接一组 3 个数字([0-9]{3})、一个连字符(-)、另外一组 3 个数字、另外一个连字符、一组 4 个数字,然后是行的结尾($)。当您手工编写表达式时,这会使您了解到正则表达式要处理的问题的复杂程度如何,从而有助于预测出使用表达式搜索或替换的数据类型。
eregi() 方法类似于 ereg(),不同之处在于它对大小写不敏感。它将返回一个包含所找到的匹配项长度的整数,但您很可能会将其用于条件语句中,如下所示:
|
执行此示例时,将输出 Found match!,这是因为在忽略大小写的搜索中找到了 hello。如果您使用的是 ereg,搜索将失败。
POSIX 替换
ereg_replace() 和 eregi_replace() 这两种方法用于在文本中进行替换,具有 POSIX 正则表达式的特性。
您可以使用 ereg_replace() 方法以 POSIX 正则表达式语法进行大小写敏感的替换。如下示例描述了如何替换带有超链接的字符串内的电子邮件地址:
|
这是一条用于匹配电子邮件地址的正则表达式的不完整版本,但它展示了与 str_replace() 等其他普通替换函数相比,ereg_replace() 的强大之处。在使用正则表达式时,您可定义搜索的规则,而不是搜索文字字符。
除忽略大小写之外,eregi_replace() 函数与 ereg_replace() 是完全相同的:
|
本例将 banana 替换为 pear,替换操作忽略了大小写。
PCRE 字符类
由于 PCRE 语法支持更短的字符类和更多的特性,因此它比 POSIX 语法更为强大。表 5 列出了 PCRE 中支持而在 POSIX 表达式中没有的部分字符类。
| 字符类 | 描述 |
|---|---|
\b |
词边界,查找词的开始和结尾 |
\d |
匹配任意数字 |
\s |
匹配任意空白,如 tab 或空格 |
\t |
匹配一个 tab 字符 |
\w |
匹配包含字母与数字的字符 |
PHP 中的 PCRE 匹配函数与 POSIX 匹配函数类似,但如果您习惯使用 POSIX 表达式,那么 PCRE 匹配函数的一项特性可能会使您感到棘手:PCRE 函数要求表达式以分隔符开始和结束。在绝大多数示例中,分隔符都是一个 /,可在引号内表达式的开始和结尾处看到。务必牢记,此分隔符并非表达式的一部分。
在 PCRE 中的最后一个分隔符后,您可添加一个修饰符来更改正则表达式的行为。举例来说,i 修饰符使正则表达式对大小写不敏感。这是与 POSIX 方法的一项重要差异,在 POSIX 中,您需要按照对大小写敏感性的需求来调用不同的方法。
preg_grep() 方法返回一个数组,其中包含通过正则表达式在其中找到匹配项的另外一个数组的全部项目。如果您有一个较大的值集,并希望对其进行搜索以查找匹配项,那么该方法非常有用。下面是一个示例:
|
在本例中,正则表达式 ^\d+$ 查找行的开始(^)和结尾($)之间包含一个或多个数字(\d+)的数组的所有元素。
preg_match() 函数使用 PCRE 在字符串中查找匹配项,它需要两个参数:regex 和字符串。您可以选择提供一个将由匹配项填充的数组、允许您修改匹配操作行为的标志,还可提供字符串中开始查找匹配项的位置(offset)。示例如下:
|
本例使用了正则表达式 ^[a-z]+$,在行的开始(^)和结尾($)之间搜索可查找到一次或多次的([a-z]+)、从 a 到 z 的任意字母。
preg_match_all() 函数为在字符串中查找到的全部匹配项构建一个数组。下例构建了一个包含句子中全部词的数组:
|
正则表达式 \b\w+\b 在词边界(\b)间查找可找到一次或多次的(\w+)单词字符。每个词都将置入输出数组 $arrayout 的一个数组元素中。
PCRE 替换
在 PHP 中进行 PCRE 替换与 POSIX 替换类似,不同之处在于使用的是 preg_replace() 而非 ereg_replace() 和 eregi_replace()。
preg_replace() 函数使用 PCRE 进行替换。它需要这样几个参数:正则表达式、替换表达式和原始字符串。您还可以选择提供希望的最大替换数,以及以所完成的替换数填充的变量。示例如下:
|
本例快速演示了捕获部分文本及使用反向引用 的方法,如 \\1。这些反向引用会插入圆括号内所匹配的任意文本中,在本例中,\\1 匹配第 1 组 (\d{3})。
在示例中,您可使用 substr 将电话号码分割开来,而对字符串只需进行少量更改,要依靠 substr 来可靠地捕获正确文本会更加困难。
如果字符串的形式可为 (555)5555555,您可将表达式修改为 ^(?(\d{3}))?(\d{3})(\d{4})$ 以查找任意圆括号。
结束语
PHP 为正则表达式提供了两种语法:POSIX 和 PCRE。本教程对 PHP 中支持 POSIX 和 PCRE 正则表达式的主要函数进行了高度概述。
使用正则表达式,您可以定义规则来进行更强大的搜索和替换操作 —— 大大超越了文字的搜索与替换。
学习
获得产品和技术
讨论
|
Nathan A. Good 是明尼苏达州 Twin Cities 的一位作者、软件工程师和系统管理员。他撰写的图书包括与 Lee Babin 等人合著的 PHP 5 Recipes: A Problem-Solution Approach(Apress 出版社,2005 年)、Regular Expression Recipes for Windows Developers: A Problem-Solution Approach(Apress 出版社,2005 年)、Regular Expressions: A Problem-Solution Approach(Apress 出版社,2005 年)及与 Kapil Sharma 等人合著的 Professional Red Hat Enterprise Linux 3(Wrox 出版社,2004 年)。 | ||