代码改变世界

第四章 字符串操作与正则表达式(5)

2016-08-01 20:42  yojiaku  阅读(1440)  评论(0编辑  收藏  举报

******** 4.6 正则表达式的介绍 (from book 《 PHP & MySQL Web Development》)
PHP 支持两种格式的正则表达式语法:POSIX 和 Perl。
用途:完成复杂的模式匹配。
难度:难
******** 4.6.1 基础知识 ******

定义:正则表达式是一种描述一段文本模式的方法。

类比:strstr()函数,是在一个字符串的某个位置(如果不指明则可能在字符串中的任何位置)匹配另一个字符串。

例子:字符处"shop"匹配正则表达式"shop",也可以匹配正则表达式"h","ho"等。

其他:除了精确匹配字符串外,还可以用特殊字符来指定表达式的元意(meta-meaning)。
 例如:使用特殊字符,可以指定一个在字符串开始或末尾肯定存在的模式,该模式的某部分可能被重复,或
 模式中的字符属于特定的某一类型。此外,还可以按特殊字符的出现来匹配。
  
******* 4.6.2 字符集和类 ******

字符集可以用来匹配属于特定类型的任何字符,是一种通配符。

例如:可以用字符作为一个通配符来代替除了换行符(\n)之外的任意字符。
 ==>正则表达式 .at 可以与"cat","sat" ,"mat"等进行匹配。(这种通配符用于OS中的文件名匹配)
 此外,使用正则表达式可以更具体地指明希望匹配的字符类型,而且可以指明字符所属的一个集合。
 例如:.at可以匹配"cat","sat","mat",也可以匹配"#at";如果要限定它是a到z之间的字符,可以这
  样声明==>[a-z]at
  任何包含在[ ]中的内容都是一个字符类 -- 一个被匹配字符所属的字符集合,
  (方括号内的表达式只匹配一个字符)
  ==>[aeiou]集合可以表示元音字母;[a-zA-Z]集合表示任何的大小写字母;
  [^a-z]集合指明字符不属于某个集(即匹配任何不在a到z之间的字符)

        表4-3 用于POSIX风格的正则表达式的字符类
————————————————————————————
            类                     匹 配       
    [[:alnum:]]            文字数字字符  '[:alpha:]' and '[:digit:]’
    [[:alpha:]]             字母字符     '[:lower:]' and '[:upper:]'
    [[:lower:]]             小写字符
    [[:upper:]]             大写字符
    [[:digit:]]               小数        0 1 2 3 4 5 6 7 8 9
    [[:xdigit:]]             十六进制数  0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f
    [[:punct:]]              标点符号    ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ' { | } ~
    [[:blank:]]              制表符和空格   space and tab
    [[:space:]]              空白字符
    [[:cntrl:]]               控制符
    [[:print:]]               所有可打印的字符  '[:alnum:]', '[:punct:]', and space
    [[:graph:]]             除空格外所有可打印的字符  '[:alnum:]' and '[:punct:]'

———————————————————————————————————————


******** 4.6.3 重复 **************

" * "符号表示这个模式可以被重复0次或多次;

" + "符号表示这个模式可以被重复1次或多次。
(这两个符号要放在要作用的表达式的后面)

例子:[[:alnum:]]+ == "至少有一个字母字符"

******** 4.6.4 子表达式 *************

将一个表达式分割成几个子表达式,例如,可以表示“至少这些字符串中的一个需要精确匹配”。

用()符号来实现:(very) * large 可以匹配“large”,“very large”,“very very large”等。

******** 4.6.5 子表达式计数 ************

用在 { } 中的数字表达式来指定内容允许重复的次数。

例子:{3}表示重复3次;{2,4}表示重复2-4次;{2,}表示至少重复2次
==> (very){1,3} 表示匹配“very”、“very very”和“very very very”。

******** 4.6.6 定位到字符串的开始或末尾 ***********

[a-z]模式将匹配任何包含了小写字母字符的字符串。无论该字符串只有一个字符,或者在整个更长的字符串中只包含
一个匹配的字符。

也可以确定一个特定的子表达式是否出现在开始、末尾或者两个位置都出现。

脱字符号(^)用于正则表达式的开始,表示子字符串必须出现在被搜索字符串的开始处。

“$”用于正则表达式的末尾,表示子字符串必须出现在被搜索字符串的末尾。

例子:^bob 在字符串开始处匹配Bob;
 com$ 匹配com出现在字符串末尾处的字符串;
 ^[a-z]$ 匹配只包含a到z之间一个字符的字符串。

******** 4.6.7 分支 ******************

使用正则表达式中的一条竖线表示一个选择。

例子:com|edu|net 匹配com,edu或net

******** 4.6.8 匹配特殊字符 **********

如果要匹配特殊字符,例如:.,{或者$,就必须在前面加上反斜杠(\)

在PHP中,必须将正则表达式模式包含在一个单引号字符串中。

******** 4.6.9 特殊字符一览 ***********

表4-4 在POSIX正则表达式中,用于方括号外面特殊字符的摘要
————————————————————————————————————
 字 符                                  意 义
  \                                      转义字符
  ^               在字符串开始处匹配
  $               在字符串末尾处匹配
  .              匹配除换行符\n之外的字符
  |                选择分支的开始(或)
  (               子模式的开始
  )              子模式的结束
  *               重复0次或多次
  +               重复1次或多次
  {               最小/最大量记号的开始
  }              最小/最大量记号的结束
  ?             标记一个子模式为可选的
——————————————————————————————————————

表4-5 POSIX正则表达式中,用于方括号里面特殊字符的摘要
————————————————————————————————————
 字 符            意 义
  \                转义字符
  ^               非,仅用在开始
  -                用于指明字符范围
————————————————————————————————————

*********** 4.6.10 在智能表单中应用 ************

在只能表单应用程序中,正则表达式有两种用途:

1.在顾客的反馈信息中查找特定的名词。

以往做法:使用字符串函数strstr(),如果想匹配"shop","customer service","retail"则需要做3次不同的搜索
 ==> strstr($string,'shop'); strstr($string,'customer service'); strstr($string,'retail');

用正则:可以同时匹配"shop","customer service","retail"
 ==> shop|customer service|retail

2.验证程序中用户的电子邮件地址。

以往做法:使用字符串函数。

用正则:对电子邮件地址的标准格式进行编码。
 (数字/标点符号 + @ +文字/数字/字符组成的字符串 + . +文字/数字以连字符组成的字符串)

 ==> ^[a-zA-Z0-9_\-.]+@[a-zA-Z0-9\-]+\.[a-zA-Z0-9\-.]+$

 其中^[a-zA-Z0-9_\-.]+表示“至少由一个字母(任意大小写)、数字、下划线、连字符、点号(.)或者
 这些字符组合为开始的字符串”
 (start the string with at least one letter,number,underscore,hyphen,or dot,or some combination
 of those);

 tip:当在一个字符类的开始或末尾处使用点号时,点号将失去其特殊通配符的意义,只能成为一个点号符号。

 @ 匹配字符 @;

 [a-zA-Z0-9\-]+与包含文字数字字符和连字符的主机名匹配;

 字符组合 \. 匹配 “.”字符;(我们在字符类外部使用点号,必须对其进行转义,让它能够匹配一个点号符号)

 [a-zA-Z0-9\-.]+$匹配域名的剩下部分(com、net等),它包含字母、数字、连字符,如果需要还可以包含更多的点号直到字符串的末尾。

************* 4.7 用正则表达式查找子字符串

在PHP中,可以使用的并且用于匹配POSIX风格的正则表达式的两个函数是ereg()和eregi()

ereg(): int ereg(string $pattern, string $string [, array &$regs]);
 
 以区分大小写的方式在 string 中寻找与给定的正则表达式 pattern 所匹配的子串。

 如果找到与 pattern 中圆括号内的子模式相匹配的子串并且使用了第三个参数regs,则

 匹配项将被存入regs数组中。
 
 $regs[1]包含第一个左圆括号开始的子串,以此类推。
 
 $regs[0]包含整个匹配的字符串。

 如果string中找到pattern模式的匹配则返回所匹配字符串的长度,如果没有找到匹配或者出错则返回FALSE,

 如果没有使用第三个参数或者所匹配的字符串长度为0,则函数返回1.

eregi():不区分大小写,其余与ereg()一样。

下面是改进的智能表单(Smart Form):

if(!mb_eregi('^[a-zA-Z0-9_\-\.]+@[a-zA-Z0-9\-]+\.[a-zA-Z0-9\-\.]+$',$email)){
    echo "<p>That is not a valid email address.</p>"."<p>Please return to the previous page and try again.</p>";
    exit;
}
$toaddress = "feedback@example.com"; //the default value
if(mb_eregi("shop|customer service|retail",$feedback)){
    $toaddress = "retail@example.com";
}else if(mb_eregi("deliver|fulfill",$feedback)){
    $toaddress = "fulfillment@example.com";
}else if(mb_eregi("bill|account",$feedback)){
    $toaddress = "account@example.com";
}else{
    $toaddress = "feedback@example.com";
}
if(mb_eregi("bigcustomer\.com",$email)){
    $toaddress = "bob@example.com";
}

 

********************** 4.8 用正则表达式替换子字符串

函数:ereg_replace() / eregi_replace()

原型:string ereg_replace(string pattern, string replacement, string search);

意义:该函数在字符串search中查找正则表达式pattern的字符串,并且用字符串replacement替换。

********************** 4.9 使用正则表达式分割字符串

函数:split()

原型:array split(string pattern, string search[, int max]);

意义:将字符串search分割成符合正则表达式模式的子字符串,然后把子字符串返回到一个数组中,max指定进入数组中的元素个数。

例子:分割电子邮件地址

#split()
$address = "username@example.com";
$arr = mb_split("\.|@",$address);
while(list($key, $value) = each($arr)){
    echo "<br />".$value;
}

 

输出结果与书上不同,书上是把分隔符也输出一行,实际是去掉了分隔符

结果:
username
example
com