正则表达式在字符串处理中的应用 高洛峰


正则表达式在字符串处理中的应用 初次接触正则表达式的人除了感觉它有些繁琐外,还会有一种深不可测的感觉。其实正则表达式就是描述字符 排列模式的一种自定义的语法规则,在 PHP 给我们提供的系统函数中,使用这种模式对字符串进行匹配、查找、替 换及分割等操作,它的应用非常广泛。例如,常见的使用正则表达式去验证用户在表单中提交的用户名、密码、E-mail 地址、身份证号码及电话号码等格式是否合法;在用户发布文章时,将输入有 URL 的地方全部加上对应的链接;按 所有标点符号计算文章中一共有多少个句子;抓取网页中某种格式的数据等等。 正则表达式并不是 PHP 自己的产物,在很多领域都会见到它的应用,除了在 Perl、C#及 JAVA 语言中应用外, 在我们的 B/S 架构软件开发中,Linux 操作系统、前台 JavaScript 脚本、后台脚本 PHP 以及 MySQL 数据库中都可以 应用到正则表达式。 正则表达式简介 正则表达式也称为模式表达式,自身具有一套非常完整的、可以编写模式的语法体系,提供了一种灵活且直观 的字符串处理方法。正则表达式通过构建具有特定规则的模式,与输入的字符串信息比较,从而实现字符串的匹配、 查找、替换及分割等操作。下例中给出了 3 个模式,都是按照正则表达式的语法规则构建的。如下所示: 不要被上例中看似乱码的字符串给吓退,它们就是按照正则表达式的语法规则构建的模式,是一种由普通字符 和具有特殊功能的字符组成的字符串。而且要将这些模式字符串,放在特定的正则表达式函数中使用才有效果。学 完本文以后就可以自由应用这样的代码了。 在 PHP 中支持两套正则表达式的处理函数库。一套是由 PCRE(Perl Compatible Regular Expression)库提供的, 与 Perl 语言兼容的正则表达式函数。使用“preg_”为前缀命名的函数,而且表达式都应被包含在定界符中,如斜线 (/)。另一套是由 POSIX(Portable Operation System interface)扩展语法的正则表达式函数,使用以“ereg_”为前缀 命名的。两套函数库的功能相似,执行效率稍有不同。一般而言,实现相同的功能,使用第一种 PCRE 库提供的正 则表达式效率略占优势。所以在本文中主要介绍使用“preg_”为前缀命名的正则表达式函数,如表 1 所示: 表 1 与 Perl 语言兼容的正则表达式处理函数 函数名 功能描述 preg_match() 进行正则表达式匹配 preg_match_all() 进行全局正则表达式匹配 preg_replace() 执行正则表达式的搜索和替换 preg_split() 用正则表达式分割字符串 preg_grep() 返回与模式匹配的数组单元 preg_replace_callback() 用回调函数执行正则表达式的搜索和替换 正则表达式的语法规则 正则表达式描述了一种字符串匹配的模式,通过这个模式在特定的函数中对字符串进行匹配、查找、替换及分 /[a-zA-z]+://[^\s]*/ //匹配网址 URL 的正则表达式 /<(\S*?)[^>]*>.*?|<.*? />/ //匹配 HTML 标记的正则表达式 /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/ //匹配 Email 地址的正则表达式 割等操作。正则表达式作为一个匹配的模板,是由原子(普通字符,例如字符 a 到 z)、有特殊功能的字符(称为元 字符,例如*、+和?等)以及模式修正符三部分组成的文字模式。一个最简单的正则表达式模式中,至少也要包含 一个原子,如“/a/”。而且在与 Perl 兼容的正则表达式函数中使用模式时,一定要给模式加上定界符,即将模式包含 在两个反斜线“/”之间。一个 HTML 链接地址的正则表达式模式如下所示: 在网页中任何属于 HTML 有效的链接标签,都可以和这个正则表达式的模式匹配上。该模式就用到了编写正则 表达式模板的原子、元字符和模式休正符三个组成部分,将其拆分后如下所示: • 定界符是使用的是两个反斜线"/",将模式放在它之间声明 • 原子用到了<、a、href、=、'、"、/、>等普通字符和\t、\r、\n 等转义字符 • 元字符使用了[]、()、|、.、?、*、+等具有特殊含义的字符 • 用到的模式修正符是在定界符最后一个反斜线之后的三个字符"s"、"i"和"m" 对于原子、元字符以及模式修正符的使用将在后面详细介绍。首先编写一个示例,了解一下正则表达式的应用。 通过 PHP 中给我们提供的 preg_match()函数,使用上例中定义的正则表达式模式。该函数有两个必选参数,第一个 参数需要提供用户编写的正则表达式模式,第二个参数需要一个字符串。该函数的作用就是在第二个字符串参数中, 搜索与第一个参数给出的正则表达式匹配的内容。如果匹配成功则返回真。代码如下所示: 在上面的代码中,使用正则表达式的语法规则,定义一个匹配 HTML 中链接标签的模式并存放在变量$pattrn 中。 又定义了一个字符串变量$content,在字符串中如果包含有效的 HTML 链接标签,则使用 preg_match()函数时,就可 以按$pattrn 模式所定义的格式搜索到链接标签。 定界符 在程序语言中,使用与 Perl 兼容的正则表达式,通常都需要将模式表达式放入定界符之间。作为定界的字符也 不仅仅局限于使用反斜线“/”。除了字母、数字和正斜线“\”以处的任何字符都可以作为定界符号,例如“#”、“!”、 “{}”和“|”等都是可以的。通常习惯都将模式表达式包含在两个反斜线“/”之间。下例是一些模式表达式的应 用,如下所示: (.+?)<\/a.*?>/ '; $content=" 技术社区"; if(preg_match($pattern, $content)) { //使用 preg_match()函数进行正则表达式的模式匹配 echo "成功匹配,在第二个参数中包含有效的 HTML 链接标签字符串。"; } else { echo "在第二个参数的字符串中搜索不到有效的 HTML 链接标签。"; } /(.+?)<\/a.*?>/ //获取链接地址 原子 原子是正则表达式的最基本的组成单位,而且在每个模式中最少要包含一个 原子。原子是由所有那些未显式指定为元字符的打印和非打印字符组成,包括所 有的大写和小写字母字符、所有数字、所有标点符号以及一些其它符号。例如 a~z、 A~Z、0~9、双引号“””、单引号“’”等。还包括一些非打印字符,如表 2 所示 列出了正则表达式中常用的非打印字符及其含义: 表 2 正则表达式中常用的非打印字符 原子字符 含义描述 \cx 匹配由 x 指明的控制字符。例如,\cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的'c'字符。 \f 匹配一个换页符。等价于\x0c 和\cL。 \n 匹配一个换行符。等价于\x0a 和\cJ。 \r 匹配一个回车符。等价于\x0d 和\cM。 \s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于[\f\n\r\t\v]。 \S 匹配任何非空白字符。等价于[^\f\n\r\t\v]。 \t 匹配一个制表符。等价于\x09 和\cI。 \v 匹配一个垂直制表符。等价于\x0b 和\cK。 元字符 利用 Perl 正则表达式还可以做另一件有用的事情,这就是使用各种元字符来搜索匹配。所谓元字符,就是用于 构建正则表达式的具有特殊含义的字符,例如的“*”、“+”、“?”等。如果要在正则表达式中包含元字符本身,使 其失去特殊的含义则必须在前面加上“\”进行转义。正则表达式有以下特殊字符,如表 3 所示: 表 3 正则表达式的元字符 元字符 含义描述 \d 匹配任意一个十进制数字,等价于[0-9] \D 匹配任意一个除十进制数字以外的字符,等价于[^0-9] \s 匹配任意一个空白字符,等价于[\f\n\r\t\v] \S 匹配除空白字符以外任何一个字符,等价于[^\f\n\r\t\v] \w 匹配任意一个数字、字母或下划线,等价于[0-9a-zA-Z_] \W 匹配除数字、字母或下划线以外的任意一个字符,等价于[^0-9a-zA-Z_] * 匹配 0 次、1 次或多次其前的原子 + 匹配 1 次或多次其前的原子 /<\/\w+>/ //使用反斜线作为定界符号合法 |(\d{3})-\d+|Sm //使用竖线“|”作为定界符号合法 !^(?i)php[34]! //使用感叹号“!”作为定界符号合法 {^\s+(\s+)?$} //使用花括号“{}”作为定界符号合法 /href='(.*)' //非法定界符号,缺少结束定界符 1-\d3-\d3-\d4| //非法定界符号,缺少起始定界符 ? 匹配 0 次或 1 次其前的原子 . 匹配除了换行符外的任意一个字符 | 匹配两个或多个分支选择 {n} 表示其前面的原子恰好出现 n 次 {n, } 表示其前面的原子出现不少于 n 次 {n, m} 表示其前面的原子至少出现 n 次,最多出现 m 次 ^或\A 匹配输入字符串的开始位置(或在多行模式下行的开头,即紧随一换行符之后) $或\Z 匹配输入字符串的结束位置(或在多行模式下行的结尾,即紧随一换行符之前) \b 匹配单词的边界 \B 匹配除单词边界以外的部分 [] 匹配方括号中指定的任意一个原子 [^] 匹配除方括号中的原子以外的任意一个字符 () 匹配其整体为一个原子,即模式单元。可以理解为由多个单个原子组成的大原子 构造正则表达式的方法和创建数学表达式的方法相似,就是用多种元字符与操作符将小的表达式结合在一起来 创建更大的表达式。正则表达式的组件可以是单个的字符、字符集合、字符范围、字符间的选择或者所有这些组件 的任意组合。元字符是组成正则表达式的最重要部分,下面将这些元字符分为几类分别讲解。 通用字符类型 通用字符类型可以匹配相应类型中的一个字符,例如“\d”可以匹配数字类型中的任意一个十进制数字。共有 6 种通用字符类型,包括“\d”和“\D”、“\s”和“\S”、“\w”和“\W”。当然也可以使用原子表制定出这种通用字符 类型,例如[0-9]和“\d”的功能一样,都可以匹配一个十进制数字。但使用通用字符类型要方便得多,如下所示: 上面两个正则表达式的模式作用一样,都是匹配电子邮件的格式。很显然使用通用字符类型“\w”要比使用原 子表“[0-9a-zA-Z_]”的格式清晰得多。 限定符 限定符用来指定正则表达式的一个给定原子必须要出现多少次才能满足匹配。有“*”、“+”、“?”、“{n}”、“{n,}” 以及“{n,m}”共 6 种限定符,他们之间的区别主要是重复匹配的次数不同。其中“*”、“+”和“{n, }”限定符都是 贪婪的,因为它们会尽可能多的匹配文字。如下所示: 元字符“*”表示 0 次、1 次或多次匹配其前的原子,也可以使用“{0,}”完成同样的匹配。同样“+”可以使用 “{1,}”表示,以及“?”可以使用“{0,1}”表示。 /a\s*b/ //“\s”表示空白原子,可以匹配在 a 和 b 之间没有空白、一个或有多个空白情况 /a\d+b/ //可以匹配在 a 和 b 之间有一个或有多个数字的情况,如 a2b、a34567b 等 /a\W?b/ //可以匹配在 a 和 b 之间有一个或有没有特殊字符,如 ab、a#b、a%b 等 /ax{4}b/ //可以匹配在 a 和 b 之间必须有 4 个 x 的字符串,如 axxxxb /ax{2,}b/ //可以匹配在 a 和 b 之间至少要有 2 个 x 的字符串,如 axxb、axxxxxxb 等 /ax{2,4}b/ //可以匹配在 a 和 b 之间至少有 2 个和最多有 4 个 x 的字符串,如 axxb、axxxb 和 axxxxb /^[0-9a-ZA-Z_]+@[0-9a-ZA-Z_]+(\.[0-9a-ZA-Z_]+){0,3}$/ //E-mail 的正则表达式模式 /^\w+@\w+(\.\w+){0,3}$/ //同上 边界限制 用来限定字符串或单词的边界范围,以获得更准确的匹配结果。元字符“^”(或“\A”)和“$”(或“\Z”)分 别指字符串的开始与结束,而“\b”用于描述字符串中每个单词的前或后边界,与之相反的元字符“\B”表示非单 词边界。例如有一个字符串“this is a test”使用的边界限制如下所示: 句号(.) 在字符类之外,模式中的圆点可以匹配目标中的任何一个字符,包括不可打印字符。但不匹配换行符(默认情 况下),相当于“[^\n]”(Unix 系统)或“[^\r\n]”(Windows 系统)。如果设定了模式修正符号“s”则圆点也会匹配换 行符。处理圆点与处理音调符“^”和美元符“$”是完全独立的,唯一的联系就是它们都涉及到换行符。如下所示: 通常,可以使用“.*?”或“.+?”组合来匹配除换行符以外的任何字符串。例如,模式“/.*?b<\/b>/”可 以匹配以“”标签开始,“”标签结束的任何不包括换行符的字符串。 模式选择符(|) 竖线字符“|”用来分隔多选一模式,在正则表达式中匹配两个或更多的选择之一。例如,模式“LAMP|J2EE” 表示可以匹配“LAMP”也可以匹配“J2EE”,因为元字符竖线“|”的优先级是最低的,所以并不是表示匹配 “LAMP2EE”或“LAMPJ2EE”。也可以有更多的选择,例如模式“/Linux|Apache|MySQL|PHP/”表示可以从中任意 匹配一组。 原子表([]) 使用原子表“[]”可以定义一组彼此地位平等的原子,且从原子表中仅选择一个原子进行匹配。如下所示: 还可以使用原子表“[^]”匹配除表内原子外的任意一个字符,通常称为排除原子表。如下所示: 另外,在原子表中可以使用负号“-”连接一组按 ASCII 码顺序排列的原子,能够简化书写。如下所示: /[apj]sp/ //可以匹配 asp、psp 或 jsp 三种,从原子表中仅选择一个原子 /[^apj]sp/ //可以匹配除了 asp、php 或 jsp 三种以外的字符串,如 xsp、ysp 或 zsp 等 /a.b/ //可以匹配在 a 和 b 之间有任意一个字符的字符串,例如 axb、ayb、azb 等 /^this/ //匹配此字符串是否是以字符串“this”开始的,匹配成功 /test$/ //匹配此字符串是否是以字符串“test”结束的,匹配成功 /\bis\b/ //匹配此字符串中是否含有单词“is”,因为在字符串“is”两边都需要有边界 /\Bis\b/ //查找字符串“is”时,左边不能为边界而右边必须有边界,如“this”匹配成功 模式单元 模式单元是使用元字符“()”将多个原子组成大的原子,被当作一个单元独立使用。与数学表达式中的括号作用 类似,一个模式单元中的表达式将被优先匹配。如下所示: 在上面的例子中,紧接着“*”前的多个原子“very”用元字符“()”括起来被当作一个单元,所以原子“(very)” 可以没有,也可以有一个或多个。 后向引用 使用元字符“( )”标记的开始和结束多个原子,不仅是一个独立的单元,也 是一个子表达式。这样,对一个正则表达式模式或部分模式两边添加圆括号将导 致相关匹配存储到一个临时缓冲区中,可以被获取供以后使用。所捕获的每个子 匹配都按照在正则表达式模式中从左至右所遇到的内容存储。存储子匹配的缓冲 区编号从 1 开始,连续编号直至最大 99 个子表达式。每个缓冲区都可以使用“\n” 访问,其中 n 为一个标识特定缓冲区的一位或两位十进制数。例如“\1”、“\2”、 “\3”等的形式进行引用,在正则表达的模式中使用时还需要在前面再加上一个 反斜线,将斜线再次转义。例如“\\1”、“\\2”、“\\3”等。如下所示: 在上例中声明了两个正则表达式,用来匹配日期格式。如果使用第一种模式则在年、月及日之间的分隔符号可 以是任意的特殊字符,完全可以不对应。但实际应用中日期格式之间的分隔符号必须是对应的,即年和月之间使用 “-”,则月和日之间也要和前面的一样使用“-”。在上述中的第二个正则表达式就可以达到这种效果。这是因为模式 “\W”加上了元字符括号“()”,结果已经被存储到缓冲区中。所以在第一个“(\W)”的位置使用“-”则下一个位 置使用“\1”引用时,其匹配模式也必须是字符“-”。 如需要使用模式单元而又不想存储匹配结果时,可以使用非捕获元字符 “?:”、“?=”或“?!'”来忽略对相 关匹配的保存。在一些正则表达式中,使用非存储模式单元是必要的,可以改变其后向引用的顺序。如下所示: 模式匹配的优先级 在使用正则表达式时,需要注意匹配的顺序。通常相同优先级是从左到右进行运算,不同优先级的运算先高后 /(Windows)(Linux)\\2OS/ //使用“\2”再次引用第二个缓冲区中的字符串“Linux” /(?:Widows)(Linux)\\1OS/ //使用“?:”忽略了第一个子表式的存储,所以“\1”引用的就是“Linux” /^\d{4}\W\d{2}\W\d{2}$/ //这是一个匹配日期的格式,如 2008-08/08 或 2008/08-08 等 '/^\d{4}(\W)\d{2}\\1\d{2}$/ //这是一个匹配日期的格式,如 2008-08-08 或 2008/08/08 等 /0[xX][0-9a-fA-F]+/ //可以匹配一个简单的十六进制数,如 0x2f、0X3AE 或 0x4aB 等 /(very )*good/ //可以匹配 good、very good、very very good 或 very very … good 等 低。各种操作符的匹配顺序优先级从高到低如表 4 所示: 表 4 模式匹配的顺序 顺 序 元字符 描 述 1 \ 转义符号 2 ()、(?:)、(?=),、[] 模式单元和原子表 3 *、+、?、{n}、{n,}、{n,m} 重复匹配 4 ^、$、\b、\B、\A、\Z 边界限制 5 | 模式选择 模式修正符 模式修正符号在正则表达式定界符之外使用(最后一个反斜线“/”之后),例如“/php/i”。其中“/php/”是一个 正则表达式的模式,而“i”就是修正此模式所使用的修正符号,用来在匹配时不区分大小写。模式修正符可以调整 正则表达式的解释,扩展了正则表达式在匹配、替换等操作时的某些功能,而且模式修正符号也可以组合使用,更 增强了正则表达式的处理能力。例如“/php/Uis”则是使用“U”、“i”和“s”三个模式修正符组合在一起使用。模 式修正符对编写简洁而简小的表达式大有帮助,在下面的表格中,列出了一些常用的模式修正符及其功能说明。如 表 5 所示: 表 5 模式修正符号 模式修正符 功能描述 i 在和模式进行匹配时不区分大小写 m 将字符串视为多行。默认的正则开始“^”和结束“$”将目标字符串作为单一的一“行”字符(甚 至其中包含有换行符也是如此)。如果在修饰符中加上“m”,那么开始和结束将会指字符串的每 一行,每一行的开头就是“^”,结尾就是“$”。 s 如果设定了此修正符,模式中的圆点元字符“.”匹配所有的字符,包括换行符。即将字符串视为 单行,换行符作为了普通字符看待 x 模式中的空白忽略不计,除非它已经被转义 e 只用在 preg_replace()函数中,在替换字符串中对逆向引用作正常的替换,将其作为 PHP 代码求 值,并用其结果来替换所搜索的字符串。 U 贪婪模式,最大限度匹配 D 模式中的美元元字符仅匹配目标字符串的结尾。没有此选项时,如果最后一个字符是换行符的话, 美元符号也会匹配此字符之前。如果设定了 m 修正符则忽略此选项 下面是几个简单的示例,用以说明上表中模式修正符的使用。在使用模式修正符时,其中的空格和换行被忽略, 如果使用其它非模式修正字符会导致错误。如下所示: • 模式“/Web Server/ix”可以用来匹配字符串“webServer”,忽略大小写和空白。 • 模式“/a.+?e/Uis”可以匹配字符串“abcdefgabcdefgabcdefg”中的“abcdefgabcdefgabcde”,而不是“abcde”, 如果不加“U”修正符则匹配“abce”。这三个模式组合可以按贪婪匹配、忽略大小写匹配以及“.”可以匹 配换行符号。 • 模式“/^is/m”可以匹配字符串“this\nis\na\ntes”中的“is”,因为使用模式修正符“m”将字符串视为了多 行,第二行的开头出现了“is”则匹配成功。默认的正则开始“^”和结束“$”将目标字符串作为单一的一 “行”(甚至其中包含有换行符也是如此)。
还剩6页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 10 金币 [ 分享pdf获得金币 ] 1 人已下载

下载pdf

pdf贡献者

tyhmj

贡献于2012-03-19

下载需要 10 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!