第一次比较系统的学习正则表达式,本篇文章以PHP语言为例来学习。
基本概念
正则表达式=普通字符(如a-z)+分隔符(正斜线(/)、hash符号(#) 以及取反符号(~))+特殊字符(称为元字符) 两者的组合;
PHP的正则有两种:POSIX和PERL(PCRE Perl Compatible Regular Expression),后者PHP支持得更好
匹配原理
简单描述下,通常是由字符串位置0开始尝试匹配,若匹配成功存储这个子串;若在某一个位置匹配失败则后移一个位置,从位置1开始重新匹配。直到匹配成功或者匹配到最后一个位置都没有找到成功的子串。
匹配模式
看名字,是不是想到了设计模式中的单例模式了呢?
- 贪婪模式
在可匹配与可不匹配的时候,优先匹配,比如量词用*或+
2. 懒惰模式
在可匹配与可不匹配的时候,优先不匹配,比如量词用?。 *? 在正则中代表非贪婪匹配模式,会尽量少的匹配字符,如果不加 ?就是贪婪模式,此时通配符会把所有字符都匹配掉
用途
- 查找:检查一个串是否包含某个子串,而子串是符合正则表达式条件的子串,最后得到所有符合条件的子串集合
- 替换:将上一条查找出来的子串替换成特定的字符串
正则分隔符
字符 | 说明 | 备注 |
/表达式/ | 一个完整的正则表达式的边界 | 若表达式内有/,需要用转义字符转义 $p="/ab//" |
#表达式# | 一个完整的正则表达式的边界2 | 若表达式内有#,需要用转义字符转义 $p="#ab/##" |
~表达式~ | 一个完整的正则表达式的边界3 | 若表达式内有~,需要用转义字符转义 $p="~ab/#~~" |
|表达式| | 一个完整的正则表达式的边界4 | 若表达式内有|,需要用转义字符转义 $p="|ab/#~||" |
元字符
边界定位符
字符 | 说明 | 备注 |
^开头, | 用于子字符串的末尾,,表示子字符串必须出现在字符串的开头 | 见代码示例1 |
$结尾 | 用于子字符串的末尾,,表示子字符串必须出现在字符串的末尾,可以和^搭配使用 | |
匹配一个单词边界,匹配单词和空格之间的位置 | ||
B | 匹配一个非单词边界,匹配单词和空格之间的位置 |
量词元字符
字符 | 说明(都是返回能得到的最长子串) | 备注 |
* | 0次或多次匹配前面的子表达式, | 等价于{0,} |
? | 0次或1次匹配前面的子表达式 | 等价于{0,1}懒惰模式就用这个 |
+ | 1次或多次匹配前面的子表达式 | 等价于{1,} |
{n} | n次匹配前面的子表达式 | |
{n,} | 大于等于n次匹配前面的子表达式 | |
{,n} | 小于等于n次匹配前面的自表达式 | |
{n,m} | 最少n次,最大m次,匹配前面的自表达式 |
普通元字符
字符 | 说明 | 备注 |
d | 数字,等价于[0-9] | digit |
D | 非数字,等价于[^0-9] | |
w | 匹配字母、数字、下划线,等价于[a-zA-z0-9_] | word |
W | 匹配非[^a-zA-z0-9_] | |
s | 匹配任何空白字符(包括空格、制表符、换页符),等价于[ f v] | space |
S | 匹配任何非空白字符(包括空格、制表符、换页符),等价于[^ f v] | |
转义字符 | ||
. | 匹配除换行符( )之外的任何字符 |
当一个字符类的开始或末尾处使用点号时,只能成为普通的点号字符 |
[] |
只能匹配一个字符,自带“或”的属性,后面可以跟修饰符。 方括号内,个别字符有不同的含义: ^仅在作为第一个字符(方括号内)时,表明字符类取反 - 标记字符范围 转义字符 |
|
() | 包含一个子表达式,要表达“或”需要“|” | |
| | 开始一个可选分支 |
分组元字符
字符 | 说明 | 备注 |
() | 将表达式括起来,与其他元字符配合使用 |
引用
字符 | 说明 | 备注 |
& | 在替换字符串中,符号&代表整个正则表达式所匹配的字符串的内容 | 仅在替换时使用 |
(n=1,2...) | 转移数字 代表索索字符串的第n个括号中正则表达式所匹配的字符串内容 | 查找、替换都能使用 |
各元字符的优先级
优先级 | 字符集 | 说明 |
1 | 转义 | |
2 | ^wd等 | |
3 | (),[] | |
4 | *,+,?,{} | 两次 |
5 | ^,$ | 断言,位置 |
6 | | | 分组 |
PHP中正则相关的几个方法
1.preg_match($pattern, $subject, $matches);
用途:返回值是匹配成功的次数0或者1,在匹配到1次以后就会停止搜索
参数:$pattern 为正则表达式;$subject为被搜索的字符串;$matches可选,存储匹配结果的数组,$matches[0]包含整个模式匹配的文本,$matches[1]为第一个括号中的子模式所匹配的文本,依次类推
代码示例:
$subject = "abcdef";
$pattern = '/a(.*)(w)d/';
preg_match($pattern, $subject, $matches);
print_r($matches);
返回结果:
Array
(
[0] => abcd
[1] => b
[2] => c
)
2.preg_match_all($pattern, $subject, $matches,$flags]);
用途:循环获取一个列表的匹配结果数组。
参数:$pattern 为正则表达式;$subject为被搜索的字符串;
$matches必选,存储匹配结果的多维数组
$flags有多个值,int类型。
case: flag=1,PREG_PARTTERN_ORDER 默认值,$matches[0]存储的是全部模式匹配的数组,$matches[1]为第一个括号中的子模式所匹配的文本array,依次类推。
$p = "|<[^>]+>(.*?)</[^>]+>|i"; $str = "<b>example: </b><div align=left>this is a test</div>"; preg_match_all($p, $str, $matches,1); print_r($matches);
运行结果:
Array
(
[0] => Array
(
[0] => <br>example: </br>
[1] =><div>this is a test</div>
)
[1] => Array
(
[0] => example:
[1] => this is a test
)
)
case: flag=2,PREG_SET_ORDER ,$matches[0]存储的是第一括号里面模式匹配的所有数组,$matches[1]为第而括号里面模式匹配的所有数组,依次类推。
代码示例:
$p = "|<[^>]+>(.*?)</[^>]+>|i"; $str = "<b>example: </b><div align=left>this is a test</div>"; preg_match_all($p, $str, $matches,2); print_r($matches);
运行结果:
Array
(
[0] => Array
(
[0] => <br>example: </br>
[1] => example:
)
[1] => Array
(
[0] =><div>this is a test</div>
[1] => this is a test
)
)
3.preg_replace($pattern, $replacement, $string);
用途:找到一个字符串匹配的子串,并交换子串之间的位置。
参数:第一个参数表示正则表达式;第二个参数表示新的位置,$1 表示所以父正则表达式list的每个元素的第一个子元素;第三个参数表示源字符串。
返回:$string
$string = 'April 15, 2014;July 16, 2015'; $pattern = '/(w+) (d+), (d+)/i'; $replacement = '$3, ${1} $2'; preg_match_all($pattern,$string,$matches,2); print_r($matches); echo preg_replace($pattern, $replacement, $string);
结果:
Array ( [0] => Array ( [0] => April 15, 2014 [1] => April [2] => 15 [3] => 2014 ) [1] => Array ( [0] => July 16, 2015 [1] => July [2] => 16 [3] => 2015 ) ) 2014, April 15;2015, July 16
常用示例
1.匹配邮箱:
'/^[a-zA-z_-.]+@[a-zA-z_-.]+.[a-zA-z_-.]+$/'
或 '/^[w-.]+@[w-.]+.[w-.]+$/'
tips:在中括号末尾的的. 是不需要转移字符的,而在中括号外的.就一定要记得加上转义
2. ^$间隔符加深理解:
$str="abcdae"; $p1='/^ab/'; $p2='/^a$/'; echo preg_match($p1,$str);//1 echo preg_match($p2,$str);//0
3.常用的一个注册页面的验证
1 $user = array( 2 'name' => 'spark1985', 3 'email' => 'spark@imooc.com', 4 'mobile' => '13312345678' 5 ); 6 //进行一般性验证 7 if (empty($user)) { 8 die('用户信息不能为空'); 9 } 10 if (strlen($user['name']) < 6) { 11 die('用户名长度最少为6位'); 12 } 13 //用户名必须为字母、数字与下划线 14 if (!preg_match('/^w+$/i', $user['name'])) { 15 die('用户名不合法'); 16 } 17 //验证邮箱格式是否正确 18 if (!preg_match('/^[w.]+@w+.w+$/i', $user['email'])) { 19 die('邮箱不合法'); 20 } 21 //手机号必须为11位数字,且为1开头 22 if (!preg_match('/^1d{10}$/i', $user['mobile'])) { 23 die('手机号不合法'); 24 } 25 echo '用户信息验证成功';