正则表达式基础
来源:互联网 发布:vs for mac 离线版 编辑:程序博客网 时间:2024/04/29 10:05
正则表达式概念源于 《神经网事件的表示法》论文中。
正则表达式就是用某种模式去匹配一类字符串的一种公式。
正则表达式的实现由多种引擎:
- 非确定性有穷自动机 NFA
- 确定性有穷自动机 DFA
- …
PHP中有两套正则函数:
- PCRE库提供的函数, 以
preg_
为前缀来命名。 - POSIX扩展提供的函数, 以
ereg_
为前缀命名。
PHP5.3 之后, 就不推荐使用POSIX正则函数库, 如程序中使用了会报 Deprecated
级别的错误。其实使用或不适用 POSIX
正则函数库二者本质上没有太大差别, 主要是一些表现形式、语法和扩展功能的差别。
php中, 一个正则表达式分为三个部分: 分隔符、表达式和修饰符:
- 分隔符: 可以是除了字母、数字、反斜线及空白字符外的任何字符(比如/、!、#、%、|、~等)。经常使用的分隔符是正斜线(/)、hash符号(#)以及取反符号(-)。考虑到可读性, 为了避免反斜线混淆, 一般不适用正斜线做分隔符。
- 表达式: 由一些特殊字符和非特殊的字符串组成, 比如
[a-z0-9_-] + @[a-z0-9_-.]+
可以匹配一个简单的电子邮件字符串。 - 修饰符: 用于开启或者关闭某种功能/模式。
测试工具
- RegexTester
- Firefox 扩展 Regular Expression Tester
元字符
元字符(Meta-Characters)
是正则表达式中具有特殊意义的专用字符, 用来规定其前导字符(即位于字符串前面的字符)在目标对象中出现的模式。
例子:
1) 匹配以字母”a”开头的单词:
\ba\w*\b
- 第一个\b匹配单词的开始
- a表示单词由a开头
- \w* 任意数量的字母或数字
- \b 单词的结束
以上正则表达式可以匹配到: adandon
、action
、a
2) 匹配一个或多个连续的数字
\d+
: 能匹配到0
、1
、555
。+
和 *
的区别在于, *
是重复0到任意次, +
则匹配至少一次或更多次。
3) 匹配刚好6个字符的单词:
b\w{6}\b
: 能匹配到action
、123456
、ste_ph
正则表达式中, 单词指不少于1个的连续字母或数字
^
、$, 匹配字符串的开头和结束, 类似于 \b
但是如果不是完整字符串匹配成功, 而是字符串的部分匹配成功, 整个表达式也是无法匹配成功的。
正则表达式中的量词
需要注意 * 和 ? , 通配符里面也有这两个符号, 要注意它们之间的区别。
如果要匹配没有预定义元字符的字符集合, 只需要在方括号中列出它们:
[aeiou]
: 匹配英语中的元音字符。
转义字符
如果要匹配元字符本身, 如果直接使用元字符, 会被解释为元字符, 这个时候就需要使用\
来转义元字符。
使用\Q
和\E
也可以忽略正则表达式元字符.
\d+\Q.$.\E$
:
- 先匹配一个或多个数字
- 紧接着匹配一个
.
, 然后再匹配一个$
, 再然后一个.
, 最后是字符串末尾
通过上面的案例可以看出, \Q 和 \E中的内容会被当作普通字符来匹配, 而不会被解释为元字符。
反义
有时候, 查找的字符不属于某个字符类, 或者表达式和以知相反, 这时需要用到反义。
常用反义
^ 表示开头, 但是如果当^ 存在字符组[] 中时, 就代表非。
分支
分支就是存在多种可能的分配情况。
如果要匹配cat 或者 hat, 可以写成[ch]at
, 但是如果要匹配cat、hat、fat、toat, 就不能用字符组来匹配了, 因为字符组只支持单个字符, 这个时候可用分支形式:(c|h|f|to) at
。
单字符的情况, 字符组效率会更改。所以能用字符组, 就不使用分支。
使用分支时, 千万要注意各个条件的顺序。
\d{5} | \d{5}-\d{4}
: 这个正则表达式就只能匹配5位数的邮编和9位数邮编的前5为。将两个分支反过来才是正常的
分组
重复单个字符只需要在字符后面加上限定符, 但是想重复多个字符该怎么办? 可以用小括号指定子表达式, 然后规定这个子表达式的重复次数。
常用分组语法
简单的IP地址匹配表达式:
(\d{1,3}\.){3}\d{1,3}
由于IP地址中每个数字不能超过255, 所以上面的正则其实是有问题的。如果能用算数比较, 或许能简单的解决这个问题, 但是正则表达式没有提供任何关于数学的任何功能, 所以只能使用冗长的分组, 选择, 字符类来表述一个正确的ip地址:
((2[0-4]\d|25[0-5]|[01]? \d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]? \d\d?)
默认每个分组会自动拥有一个组号, 规则是: 从左向右, 以分组的左括号为标志, 第一个出现的分组, 其组号为1, 第二个为2, 以此类推; 分组0对应整个表达式。
也可以自己指定子表达式祖名:
?<Word> \w+
可以把尖括号换成单引号:
?'Word' \w+
反向引用
反向引用用于重复搜索前面某个分组匹配的文本。
\b(\w+)\b\s+\1\b
\1 代表匹配分组1匹配的文本
也可以写成:
\b(?<Word>\w+)\b\s + \k<Word>\b
用\k<Word>
来匹配自定义分组名
环视
断言用来声明一个应该为真的事实。正则中, 只有当断言为真时才会继续进行匹配。
断言匹配的是一个事实, 而不是内容。
1. 顺序肯定环视(? = exp)
零宽度正预测先行断言, 又称顺序肯定环视, 断言自身出现位置的后面能匹配表达式exp。
\b\w+ (?=ing\b)
: 匹配以ing结尾单词前面部分
用上面正则查找下面的句子, 会匹配sing 和 danc
I’m singing while you’re dancing.
2. 逆序肯定环视(? <= exp)
零宽度正回顾后发断言, 又称逆序肯定环视, 断言自身出现位置的前面能匹配表达式exp。
(?<=\bre)\w + \b
: 匹配以re开头的后半部分
用上面正则查找下面的句子, 会匹配 “ading”
reading a book
3. 顺序否定环视(?!exp)
零宽度负预测先行断言, 又称顺序否定环视, 断言此位置后面不能匹配表达式exp。
1) 匹配三位数字, 而且这3为数字后面不能是数字:
\d{3}(?!\d)
2) 匹配不能包含联系字符串abc的单词:
\b((?!abc)\w) + \b
4. 逆序否定环视(?
贪婪/懒惰匹配模式
当正则表达式中包含内接受重复的限定符时, 通常的行为是(在使整个表达式能够得到匹配的前提下)匹配尽可能多的字符。
a.*b
用来匹配以a开始, 以b结束最长字符串, 如果用来搜索aabab, 它会匹配整个字符串。
如果需要匹配尽可能少的字符, 也就是懒惰匹配。 a.*?b
将前面的贪婪匹配转化为懒惰匹配模式, 只要在后面加上一个问号。
正则另外一条规则: 最先开始的匹配拥有最高优先权。
懒惰限定符
懒惰匹配模式的原则是, 在匹配和不匹配都可以的情况下, 优先不匹配, 记录备选状态, 并将匹配控制交给正则表达式的下一个匹配符。当后面的匹配失败时, 回溯, 进行匹配。
在一定情况下, 使用懒惰模式可以减少回溯, 提高效率。
构造正则表达式
在理解正则过程中, 通常是由简到繁的过程, 理解正则内部间的关系, 就可以把复杂的正则拆分成多个小块来理解
1) 正则表达式的逻辑关系
正则表达式之间的关系可以简单用 与、或、非 来表述。
2) 运算符优先级
正则表达式从左到右进行计算, 并遵循优先级顺序, 这与算术表达式非常类似。下面表列出了正则运算符的优先级顺序, 优先级从上到下, 由高到低排列。
3) 正则表达式的常用模式
模式(Pattern Modifiers
) 就是可以改变表达式行为的字符, 用来关闭或打开某些特殊功能, 习惯上又称正则修饰符。
- 忽略大小写模式 (i)
if (preg_match('% <div>gg<\/div>%i', "<div>gG</Div>", $arr)) { echo "匹配成功:" . $arr[0];} else { echo "匹配失败";}
忽略大小写是正对整个表达式而言, 而不仅仅是欲匹配的部分。如果只想修饰部分表达式, 可以使用PCRE的内部选项——”局部修饰符”
如: #ab(?i)c#
只能匹配abc 和 abC, 而不会匹配Abc;
- 多行模式(m)
正则表达式默认开始^
和结束$
只是针对正则字符串, 如果修饰符加上m, 开始和结束将会指定字符串的每一行: 即每一行的开头就是^
, 结尾就是$
。
m表示多行匹配, 而不是跨行匹配。仅当表达式中出现^、$中至少一个元字符且字符串有换行符\n时, m修饰符才起作用, 否则会被忽略。
$str = "this is regRegthis isregexp turtor, oh reg";if(preg_match_all('%.*reg$%mi', $str, $arr)) { echo "匹配成功"; var_dump($arr);} else { echo "匹配失败";}
在预想中, 使用了m多行匹配, 应该会匹配到第一行和第四行。
匹配成功 array(1) { [0] => array(1) { [0] => string(20) "regexp turtor, oh reg" }}
但是实际上只匹配了一行。这里即使去掉m结果也是一样, 这说明$只能表示最后一行。把正则表达式改为:
%^t.*%mi
结果为:
匹配成功 array(1) { [0] => array(1) { [0] => string(20) "regexp turtor, oh reg" }}
匹配到2行, 去掉m只匹配到一行。可见即使加了m修饰符, 也不是将这个字符串都匹配, 这就是跨行和多行的区别。
使用 m 一定要注意换行符是否真的有效
- 点号通配模式(s)
作用是使正则表达式里的点号元字符可以匹配换行符, 如果灭有这个修饰符, 点号不匹配换行符。
$str = "this is regRegthis isregexp turtor, oh reg";if(preg_match_all('%this.*?reg%i', $str, $arr)) { echo "匹配成功"; var_dump($arr);} else { echo "匹配不成功";}
如果正则改为$this.*?reg%is
, 那么匹配结果就不同了
匹配成功 array(1){ [0] => array(2) { [0] => string(11) "this is reg" [1] => string(13) "this is reg" }}
- 懒惰模式(U)
相当于前面提到的”?”, 表示懒惰匹配
- 结尾限制(D)
如果使用$限制结尾字符, 则不允许结尾有换行符, 例如下面表达式匹配”abc”、”abs\n” 这样的字符, 即忽视结尾的换行:
%abc$%
如果使用D 模式, 限定其不可有换行, 必须以abc结尾:
%abc$%D
- 支持UTF-8转义表达(u)
启用PCRE中与perl不兼容的额外功能, 模式字符串被当成UTF-8。
正则表达式的效率和优化
正则表达式可以看作描述字符串匹配的算法代码, 本质上说是一种有限状态机在计算机中的表示方法。
1. 使用字符组代替分支条件。
2. 优先选择最左端的匹配结果。
3. 标准量词是匹配优先的。
4. 谨慎使用点号元字符, 尽可能不要用星号和加号这样的任意量词。
php的PCRE扩展提供了两个设置项:
- pcre.backtrack_limit //最大回溯数
- pcre.recursion_limit //最大嵌套数
默认backtarck_limit 是10万, recursion_limit限制最大正则嵌套层数。在正则表达式的使用中, 应尽量避免回溯次数过多的情况。
5. 能用懒惰匹配就坚决不使用贪婪匹配
6. 尽量使用字符串函数处理代替
7. 合理使用括号
每使用一个普通括号, 而不是非捕获行括号(?:…), 就会保留一部分内存等着再次访问。这样的正则表达式、无限次的运行次数, 无异于一根根堆积的稻草, 迟早会将骆驼压死。
8. 起始、行描点优化
能确定起始位置, 使用^能提高匹配的速度。使用$标记结尾, 正则引擎则会从符合条件的长度开始匹配, 略过目标字符串许多可能的字符。
9. 量词等价转换的效率差异
10. 对大而全的表达式进行拆分
11. 使用正则以外的解决方案
- 正则表达式基础表达式
- 正则表达式基础
- 正则表达式基础
- 正则表达式基础
- 正则表达式基础
- 正则表达式基础
- 正则表达式基础
- 正则表达式基础
- 正则表达式基础
- 正则表达式基础
- 正则表达式的基础
- 正则表达式基础
- 正则表达式基础
- 正则表达式入门基础
- 正则表达式基础
- Javascript正则表达式基础
- 正则表达式基础
- 正则(正规)表达式基础
- IDE、SATA、SCSI、SAS、FC、SSD 硬盘类型
- PHP实现队列及队列原理
- 深入理解HTTP协议及原理分析
- adb命令
- 总结最近一周所作所为,主要归结为学习了android源生输入法原理和WPF界面导出功能客制化
- 正则表达式基础
- Math类的方法
- Eureka Server Replicate
- Silver Cow Party(好题)
- 383. Ransom Note | 字符串
- AndroidStudio集成SVN
- 【Video】RTSP协议、RTMP协议、HTTP协议的区别
- HTML5&Web开发关于一键拨号和发送短信
- 小鱼的游泳时间