正则表达式学习笔记(一)基础知识
一、什么是正则表达式?
正则表达式就是用某种模式去匹配一类字符串的一种公式。
二、正则表达式的组成
在php中,正则表达式由三部分组成:分隔符、表达式和修饰符。
- 分隔符:一般用:正斜线(/)、#、~或者%。
- 表达式:由可以表示其他字符串的字符组成
- 修饰符:可以开启或关闭某种功能(忽略大小写、多行匹配等)
1.实例
preg_match_all('%.*reg$%mi', $str, $arr);
上面是一个php的正则表达式,参数为:
- 正则表达式
- 待匹配字符串
- 匹配到的字符串
三、测试工具
写出正则表达式就需要测试,测试工具很重要。一般来说,用在线正则匹配工具就可以满足要求,或者使用语言自带的正则函数。
四、元字符
26个字符可以组成任何单词。而元字符,可以通过组合去匹配到任何能见到的字符串。
元字符 | 描述 |
---|---|
. | 匹配除换行符以外的任意字符 |
\w | 匹配字母、数字、下划线或者汉字 |
\s | 匹配任意空白符 |
\d | 匹配数字 |
\b | 定界符:匹配单词开始或者结束 |
^ | 匹配字符串开始 |
$ | 匹配字符串结束 |
- | 表示范围 |
[] | 匹配括号中任一字符 |
* | 量词:表示任意多个 |
+ | 量词:一个或者多个 |
? | 量词:一个或者没有 |
{} | 量词:在括号范围之内 |
\W | 匹配任意不是字母、数字、下划线或者汉字的字符 |
\S | 匹配非空白的字符 |
\D | 匹配非数字 |
\B | 匹配非单词开始或者结束 |
五、匹配规则
1.字符组
[aeiou] 匹配括号中的任何一个字母
c[aou]t 匹配 cat/cot/cut 而不能匹配caout
[] 匹配单个字符
2.转义
元字符表示特殊的含义,如果想匹配元字符就需要用到转义。转义需要在需转义的字符钱加反斜线(\)。
(.)表示任意字符,而(.)则表示 . 这个字符
(\w)表示word、而(\w)则表示 \w 这个字符串
3.分支
分支就相当于编程时遇到了if语句。
[ch]at 可以匹配 cat/hat
(c|h|f|to)at 可以匹配 cat/hat/fat/toat
在匹配时、就相当于遇到了选择语句,需要判断之后再匹配
分支检测为if/else语句,遇到if中条件为真则不会继续匹配
4.分组
分组的作用就是将多个字符看做是一个整体。
.* 表示任意字符重复任意次
(abc)* 表示abc这个字符串以相同的顺序重复任意多次
<table class="table table-bordered table-striped table-condensed">
<tr>
<td>类别</td>
<td>语法</td>
<td>描述</td>
</tr>
<tr>
<td rowspan=3 align='center'>捕获</td>
<td>(exp)</td>
<td>匹配exp,并捕获文本到自动命名的组里</td>
</tr>
<tr>
<td>(?《name》exp)</td>
<td>匹配exp,并给匹配到的文本命名,也可以写成(?'name'exp)</td>
</tr>
<tr>
<td>(?:exp)</td>
<td>匹配exp并且不给此分组分配组号</td>
</tr>
<tr>
<td rowspan=4 align='center'>零宽断言</td>
<td>(?=exp)</td>
<td>匹配exp前面的位置</td>
</tr>
<tr>
<td>(?《=exp)</td>
<td>匹配exp后面的位置(英文小于号无法显示,用书名号代替)</td>
</tr>
<tr>
<td>(?!exp)</td>
<td>匹配后面跟的不是exp的位置</td>
</tr>
<tr>
<td>(?《!exp)</td>
<td>匹配前面不是exp的位置(英文小于号无法显示,用书名号代替)</td>
</tr>
<tr>
<td>注释</td>
<td>(?#comment)</td>
<td>提供注释,不对表达式产生影响</td>
</tr>
</table>
5.反向引用
\b(\w+)\b\s+\1\b
这个可以匹配 go go 或者 a a
\1 指的是在前面第一个捕获的分组
也可以使用这个 \k< Word >
\b(?< Word >\w+)\b\s+\k < Word > \b
6.环视
正则匹配有四种环视方式:
- 顺序肯定环视(零宽度正预测先行断言)
- 逆序肯定环视(零宽度正回顾后发断言)
- 顺序否定环视(零宽度负预测先行断言)
- 逆序否定环视(零宽度负回顾后发断言)
四种方式对应的表达式分别为:
- (?=exp)
- (?<=exp)
- (?!exp)
- (?<!exp)
乍一看确实很难理解,但是我这里有更好的理解方式:
- 零宽度代表,匹配的时候只匹配位置,而不将匹配到的内容放到结果中
- 正预测和正回顾则代表着,匹配到的位置存在是对的
- 负预测和负回顾则代表着,匹配到的位置不存在才是对的(非)
- 先行断言就像是你在预测一件事情,预测后面发生的就是这样的(在表达式后面发生)
- 后发断言就像是事情已经发生了,然后才说出来这件事情(在表达式前面发生)
理解了以上几条之后,你就可以开始写复杂的正则表达式了。
例子:
(?<![a-z])\d{7} 前面不是小写字母的7位数字
7.贪婪、懒惰匹配
.* 表示贪婪匹配,能匹配更多就匹配多个
.*? 表示懒惰匹配,在能匹配更多个的时候优先不匹配
懒惰限定符 | 描述 |
---|---|
*? | 重复任意次,但尽可能少重复 |
+? | 重复1次或更多次,但尽可能少重复 |
?? | 重复0次或1次,但尽可能少重复 |
{n,m}? | 重复n到m次,但尽可能少重复 |
{n,}? | 重复n次以上,但尽可能少重复 |
六、模式
1.忽略大小写(i)
一般忽略大小写时为全局生效,若想部分生效需要如此:
#ab(?i)c#
此表达式会匹配abc和abC
2.多行模式(m)
<?php
// 多行模式的本质是检查是否有 \n 换行符
$source1 = 'abc\nabcd';
$source2 = "abc\nabcd";
if (preg_match_all('%^abc%m', $source1, $arr)) {
echo "匹配成功--";
var_dump($arr);
} else {
echo "匹配不成功--";
}
if (preg_match_all('%^abc%m', $source2, $arr)) {
echo "匹配成功--";
var_dump($arr);
} else {
echo "匹配不成功";
}
3.点号通配模式
点号通配模式的作用是使正则表达式的点号元字符能匹配换行符,如果没有这个修饰符,点号不匹配换行符。
// 点号通配模式(s),使点号可以匹配换行符
$str = "<body><div class='content'>
<div class='head'></div>
<div class='body'></div>
<div class='foot'></div>
</div></body>";
$arr1 = $arr2 = array();
preg_match_all('%<body>(.*)<\/body>%', $str, $arr1);
var_dump($arr1); // 为空
preg_match_all('%<body>(.*)<\/body>%s', $str, $arr2);
var_dump($arr2); // 匹配成功
4.懒惰模式(U)
加上懒惰模式,相当于在.*后面加上问号。
5.结尾限制(D)
加上结尾限制,则结尾不能有换行符
6.支持UTF-8转义表达(u)
启用u模式,模式字符串被当成utf-8。php4.1可用。
// 支持 UTF-8 转义表达 (u)
$str = "php 编程";
if (preg_match("/^[\x{4e00}-\x{9fa5}]+$/u", $str)) {
echo "该字符串都是中文";
} else {
echo "该字符串不全是中文";
}
七、实例
1.匹配email
\w{3,16}@\w{1,64}\.\w{2,5}
2.匹配手机号码
1\d{10}
3.将UBB标签解析成HTML
<?php
$str = '[url]1.gif[/url][url]2.gif[/url][url]3.gif[/url]';
$reg = "#\[url\](.*?)\[\/url\]#"; // 此处使用懒惰模式匹配,否则会一直匹配到最后的标签
$s = preg_replace($reg, "![](http://image.baidu.com/$1)", $str);
echo $s;
八、其他
1.与:
- abc
- 肯定环视
2.或:
- a?
- 字符组
3.非:
- ^a
- \D \W \B
- 否定环视
4.优先级
从大到小
- 转义符 \
- 括号和中括号
- 量词限定符 */+/?等
- 定位点和序列 ^/$/ 元字符、连字符
- 替换 |