PHP程序设计读书笔记九之正则表达式

正则表达式
PHP支持两种不同类型的正则表达式:POSIX和Perl兼容的。POSIX正则表达式比Perl兼容的功能弱,并且有时速度慢,但是易于阅读。
正则表达式的三种作用:匹配,用于从字符串提取信息;用新文本取代匹配的文本;把字符串拆分成小块的数组。
1.基础:
①在正则表达式中有特殊含义的字符:
1)在正则表达式开头的^符号表示它必须匹配字符串的开头(更准确的说是把正则表达式定位在字符串开头);
ereg('^cow','Dave was a cowhand');//返回false
ereg('^cow','cowbunga');//返回true
2)在正则表达式末尾出现的$表示他必须匹配字符串的末尾(也就是说,把正则表达式定位在字符串的末尾);
ereg('cow$','Dave was a cowhand');//返回false
ereg('cow$','Don't have a cow');//返回true
3)在正则表达式中的句点(.)匹配任意单个字符:
ereg('c.t','cat');//true
ereg('c.t','c t');//true
ereg('c.t','ct');//false
②如果想要匹配特殊字符中的某一个字符(称为元字符),需要使用反斜杠对它进行转义
ereg('\$5\.00','Your bill is $5.00 exactly');//返回true
ereg('$5.00','Your bill is $5.00 exactly');//返回false
③正则表达式默认不区分大小写,所以"cow"和"COW"是不匹配的,如果想要执行一个不区分大小写的POSIX风格的匹配,可以使用eregi()函数。
④正则表达式中三种基本的抽象模式
1)字符集:可以通过用中括号"[]"包含可接受的字符来建立自己的字符类。
ereg('c[aeiou]t','I cut my hand');//true
ereg('c[aeiou]t','This crusty cat');//true
ereg('c[aeiou]t','What cart?');//false
ereg('c[aeiou]t','14ct gold');//false
执行原理分析:如果正则表达式引擎发现一个"c",然后匹配下一个字符是否是中括号中的字符中的一个(这里即为'a'或'e'或'i'或'o'或'u'中的一个),
如果不是,则匹配失败,引擎继续去查找字符串中的另一个'c';
如果是,引擎继续检查下一个字符是否是't';
如果是,引擎达到匹配的末尾并返回true;
如果不是,则引擎去查找另一个c;
查找不到,直接退出;
找到,继续按照上面的匹配规则匹配;
如果没找到,直接返回false.
可以在字符类开头使用^来否定该类:
ereg('c[^aeiou]t','I cut my hand');//false
ereg('c[^aeiou]t','Reboot chthon');//true
ereg('c[^aeiou]t','14ct gold');//false
在这里正则表达式引擎查找一个'c',然后是一个非元音字符,接着是一个't'
可以用连字符(-)定义一个字符范围
ereg('[0-9]%','we are 25% complete');//true
ereg('[0123456789]%',we are 25% complete);//true
ereg('[a-z]t','2th');//false
ereg('[a-z]t','cet');//true
ereg('[a-z]t','PIT');//false
ereg('[a-zA-Z]!','stop!');//true
2)可选择性集合
可以使用竖线(|)字符在正则表达式中指定可供选择的部分。
ereg('cat|dog','the cat rubbed my legs');//返回true
ereg('cat|dog','the dog rubbed my legs');//返回true
ereg('cat|dog','the rabbit rubbed my legs');//返回false
如果想要一行只有cat或dog,需要使用正则表达式'^(cat|dog)$'
如果想要某个字符串不以大写字母开头,需要使用正则表达式'^([a-z]|[0-9])'
3)在字符串中重复的序列
要指定重复模式和量词,量词在重复模式后面,用来说明要重复这个模式多少次
POSIX和Perl都支持的量词及其含义:
? => 重复次数为0或1
* => 重复次数为0或更多
+ => 重复次数为1或更多
  {n} => 重复次数为n
 {n,m} => 至少n次,最多m次
  {n,} => 至少n次
ereg('ca+t','caaaaaaat');//true
ereg('ca+t','ct');//false
ereg('ca?t','caaaaaaat');//false
ereg('ca*t','ct');//true
使用量词和字符类来匹配美国的电话号码:
ereg('[0-9]{3}-[0-9]{3}-[0-9]{4}','303-555-1212');//true
ereg('[0-9]{3}-[0-9]{3}-[0-9]{4}','64-9-555-1234');//false
2.子模式:可以使用小括号把几个正则表达式组合在一起作为一个单独的单元来对待,这个单元被称为子模式
ereg('a (very )+big dog','it was a very very big dog');//true
ereg('^(cat|dog)$','cat');//true
ereg('^(cat|dog)$','dog');//true
小括号也使得与子模式匹配的字串被捕获,如果把一个数组当做第三个参数传递给匹配函数,任何捕捉到的子串都将被放进该数组。
数组的第1个元素是与第一个子模式匹配的子串,第二个元素是与第二个子模式匹配的子串,以此类推。数组的第0个元素为所有子模式匹配到的字符串的合集(就是由后面所有的非空元素的连接而成的字符串)。

example:

<?php
			$arr = null;
			ereg('([0-9]+)','You have 42 magic  beans',$arr);
			print_r($arr);
			ereg('([0-9]+)([0-9]+)','You have 42 magic 55 beans',$arr);
			print_r($arr);
		?>
输出:


3.风格正则表达式:
POSIX正则表达式
①字符类:
=> 描述
[:alnum:] => 字母和数字字符[0-9a-zA-Z]
[:alpha:] => 字母字符[a-zA-Z]
[:ascii:] => 7位ASCII字符[\x01-\x7F]
[:blank:] => 水平空白符(空格、制表)[ \t]
[:digit:] => 数字[0-9]
[:lower:] => 小写字母[a-z]
[:upper:] => 大写字母[A-Z]
[:punct:] => 任意的标点符号[.;!#<>=+...]
[:space:] => 空白(换行、回车、制表符、空格、垂直制表符)[\n\r\t \x0B]
[:xdigit:] => 16进制数字[0-9a-fA-F]
每一个[:something:]类都可以被用于替代一个字符类中的字符。例如:要查找任一数字字符或大写字母 => [[:digit:][:upper:]]
但是不能把一个字符类当做一个范围的终点来使用:
ereg('[A-[:upper:]]','string');//非法的正则表达式
如果某个地区把某些字符序列当做一个单独的字符来考虑——————它们被称为排序序列。在字符类中匹配这些多字符序列中的一个时,要把它用[.和.]括起来。例如:[st[.ch.]]//用于匹配s、t或ch
等价类:把字符用[=和=]括起来指定,等价字符类匹配有相同整理顺序的字符。
②锚:将匹配限制在字符串中特定位置。
POSIX锚:
^ => 在字符串开始
$ => 在字符串末尾
[[:<:]] => 单词开始
[[:>:]] => 单词末尾
精确匹配某个单词:('[[:<:]]gun[[:>:]]')//精确匹配gun这个单词
③函数
POSIX风格的正则表达式有3类函数:匹配、替换和拆分。
1)匹配
ereg()函数:
原型:$found = ereg(pattern,string[,array]);
如果第三个函数指定的话就组装该数组,并根据是否存在字符串找到模式的一个匹配而返回true或false
2)替换
$changed = ereg_replace(pattern,replacement,string);
第一个参数:要替换的字符串的模式
第二个参数:要用来替换的内容
第三个参数:原字符串
返回值:原字符串被replacement替换后的字符串
3)拆分
split()函数使用正则表达式来把字符串拆分成较小的块,作为一个数组返回。如果出现错误,则split()返回false
$arr = split(pattern,string[,limit]);
第一个参数:用于匹配分隔成块的文本;
第三个参数:用于限定要拆分成多少个小块,如果设置了该值,则数组的最后一个元素会存放剩余的字符串。
返回值:子串构成的数组;
Perl兼容正则表达式
1)分隔符:
Perl风格的正则表达式模仿Perl模式的语法,即每个模式都必须用一对分隔符括起来。习惯上使用左斜杠(/),例如:/pattern/
不过任意非数字字母的字符(除了反斜杠(\))都可用于分隔一个Perl风格的模式,这在匹配包含斜杠的字符串是很有用的
后缀选项:放在结束分隔符后面的单个字符修饰符,它用于修改正则表达式引擎的行为。
后缀选项x可以让正则表达式引擎匹配前从正则表达式中跳过空白符和被#标记的注释。
下面两种方式是等价的:
1.'/([[:alpha:]]+)\s+\1/'
2.'/( # start capture'
 [[:alpha:]]+ # a word
 \s+ #whitespace
 \1 # the same word again
 ) # end capture
 /x'
2)匹配行为:Perl正则表达式特别为单行文字匹配进行了优化
句点(.)匹配任意除换行符(\n)之外的字符
美元符号($)匹配字符串的末尾或在换行符之前以换行符结尾的字符串
3)字符类:
Perl风格的正则表达式不仅支持POSIX字符类,还定义了一些自己的字符类。
\s => 空白符[\r\n \t]
\S => 非空白符[^\r\n \t]
\w => 单词字符[0-9a-zA-Z_]
\W => 非单词字符[^0-9a-zA-Z_]
\d => 数字[0-9]
\D => 非数字[^0-9]
4)锚
\b => 单词边界(在\w和\W之间或在字符串开头或末尾)
\B => 非单词边界(在\w和\w或\W和\W之间)
\A => 字符串开头
\Z => 字符串末尾或在末尾的\n之前
\z => 字符串末尾
^ => 行的开头(或如果/m标志启用的话在\n之后)
$ => 行的末尾(或如果/m标志启用的话在\n之前)
5)量词和贪婪性
Perl也支持POSIX的量词,而且是具有贪婪性(当有一个量词时,引擎在仍然满足匹配模式的情况下尽可能多的进行匹配)的。
preg_match('/(<.*>)/','do <b>not</b> press the button',$match);//在这里<b>、</b>和<b>not</b>都满足匹配条件,但是根据贪婪性原则,匹配的内容为<b>not</b>
在你需要使用最少匹配(非贪婪匹配)的时候可以使用非贪婪量词
Perl提供了一组用于最小匹配的量词(在普通量词(普通量词默认为贪婪量词)的基础上附加一个?号)
贪婪量词 => 非贪婪量词
? => ??
* => *?
+ => +?
  {m} => {m}?
  {m,n} => {m,n}?
  {m,} => {m,}?
preg_match('/(<.*>)/','do <b>not</b> press the button',$match);//在这里$match为<b>
另外一个更快的方法是使用一个字符类来匹配每个非大于字符到下一个大于字符:
preg_match('/(<[^>]*>)/','do <b>not</b> press the button',$match);
6)非捕获匹配
如果把模式的一部分用小括号括起来,那么匹配子模式的文本被捕获并且可以在后面访问。
如果你想创建一个不捕获匹配文本的子模式,那么在Perl兼容正则表达式中可以使用(?:subpattern)结构
preg_match('/(?:ello)(.*)/','jello giafra',$match);//这里$match[1]是' biafra',而不是子模式(?:ello)匹配的ello,表明第一个子模式的匹配文本没有被捕获
7)逆向引用:可以使用一个逆向引用来引用模式中之前被捕获的字符串;\1引用第一个子模式的内容,\2引用第二个,以此类推。如果嵌套了子模式,那么第一个引用以第一个左小括号开始,第二个引用以第二个左小括号开始,以此类推,不能捕获超过99个子模式
preg_match('/([[:alpha:]]+)\s+\1/','Paris in the the spring',$m);//$m[1]是'the'
8)后缀选项
Perl风格的正则表达式允许把单个字符选项(标志)放在正则表达式模式后面来修改匹配的解释或行为。
/i => 不区分大小写的匹配
/s => 使句点(.)匹配任何字符,包括换行符(\n)
/x => 从模式中删除空白符和注释
/m => 使^匹配换行符(\n)之后的内容,$匹配换行符(\n)之前的内容
/e => 如果替换字符串是PHP代码,使用eval()执行该代码来得到实际的替换字符串
PHP的Perl兼容正则表达式也支持在Perl中不支持的其他修饰符
/U => 颠倒子模式的贪婪性;*和+尽可能少地匹配而不是尽可能多
/u => 把模式字符串当做UTF-8编码对待
/X => 如果反斜杠之后跟着没有特殊意义的字符,将产生一个错误
/A => 把锚定位在字符串的开头就像模式中有^一样
/D => 使$字符仅匹配一行的末尾
/S => 使表达式解析器更加小心的检查模式的结构,使得第二次(例如:在循环中)运行时加快速度
在一个子模式中可以同时使用多个选项:/****
9)内联选项
除了在模式结束分隔符之后指定模式选项之外,还可以在一个模式内部指定仅运用于部分模式的选项
语法:(?flags:subpattern)
preg_match('/I like (?i:PHP)/','I like pHp');//在这个实例中只有单词PHP是不区分大小写的
i、m、s、U、x和X选项可被用在这种方式内部。一次可以使用多个选项。
preg_match('/eat (?ix:fo o   d)/','eat FoOD');//true
一个选项前如果有连字符(-)表示关闭此选项
preg_match('/I like (?-i:PHP)/','I like pHp');//false
内置标志不能用于捕捉字符串,需要设置一个附加的小括号来完成捕捉。
preg_match('/I (like  (?i)PHP) a lot/','I like pHp a lot',$match);//$match为like pHp
10)前向和后向断言(看不懂,暂时跳过)
11)剪切(一次性子模式),可以防止正则表达式在对待某些类型的模式时出现最坏的情况,一旦匹配,正则表达式就不会回溯子模式。
剪切不会改变匹配的结果,只是让程序能尽快运行结束。
12)条件表达式:在正则表达式中条件表达式就像一个if语句。
一般格式为:(?(condition)yespattern)//如果条件成立,就试图匹配yespattern
(?(condition)yespattern|nopattern)//如果条件成立,就试图匹配yespattern,否则,就尝试匹配nopattern
断言可以是两种类型中的一种:逆向引用或前向和后向匹配

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值