PHP基本整理2
正则表达式
什么叫正则表达式
正则表达式是对字符串进行操作的一种逻辑公式,就是用一些特定的字符组合成一个规则字符串,称之为正则匹配模式。
$p ='/apple/';
$str = "apple banana";
if(preg_match($p,$str)){
echo 'matched';
}
比如 $s='/apple/'
就是一个正则表达式,匹配源字符串中是否存在apple字符串。PHP中使用PCRE库函数进行正则匹配。比如上例中的preg_match用于执行一个正则匹配,常用来判断一类字符模式是否存在。
正则表达式基本语法
PCRE库函数中,正则匹配模式使用分隔符与元字符组成,分隔符可以是非数字、非反斜杠、非空格的任意字符。经常使用的分隔符是正斜杠(/)、hash符号(#)以及取反符号(~)。使用正则表达式的目的是为了实现比字符串处理函数更加灵活的处理方式,因此跟字符串处理函数一样,其主要用来判断子字符串是否存在、字符串替换、分割字符串、获取模式子串等。
- 如果模式中包含分隔符,分隔符需要用反斜杠(\)进行转义
/http:\/\//
- 如果模式中包含较多的分割字符,建议使用其他字符作为分隔符,也可以采用preg_quote进行转义。如下:
$p = '/''.preg_quote($p,'/').'/
上述代码就用preg_quote转义了'/' - 分隔符后面可以使用模式修饰符,模式修饰符后面给出如:i,m,s,x有附加效果
$str = "Http://www.baidu.com/"
if (preg_match('/http/i',$str)){
echo '匹配成功';
}
- 常用修饰符:i,g,m,s,x,e
- 修饰符 i:不区分大小写(Ignore)
- 修饰符g: 全局匹配(Global)
- 修饰符m:字符串视为多行,不管哪行都能匹配,更改了^和$的含义,每一行的行首行尾都行(Multiline)
- 修饰符s:字符串视为单行,换行符作为普通字符(Singleline)
- 修饰符x:将模式中的空白忽略
- 修饰符U:只匹配最近的一个字符串,不重复匹配(Unique)
- 修饰符e:配合函数preg_replace()使用,可以把匹配来的字符串当作正则表达式执行
元字符与转义
转义字符用''转义。元字符指的是正则表达式中有特殊含义的字符:
- .匹配除换行符以外的任意字符
- \w匹配字母或数字或下划线或汉字
- \s匹配任意的空白符
- \b匹配单词的开始或结束
- ^匹配字符串的开始
- $匹配字符串的结束
反义
- \W匹配与\w相反
- \S匹配任意不是空白符的字符
- \D匹配任意非数字的字符
- \B匹配任意不是单词开头或结束的字符
- [^x]匹配任意不是x的字符
- [^aeiou]匹配除了aeiou这几个字符之外的任意字符
例子:
/\S+/
匹配不包括空白符的字符串
/<a[^>]+>/
匹配用尖括号括起来的以a开头的字符串
重复
- *重复0次或更多
- +重复1次或更多
- ?重复零次或1次
- {n}重复n次
- {n,}重复n次或更多次
- {n.m}重复n到m次
贪婪和懒惰
- *?重复任意次但尽可能少
- +?重复一次或多次但尽可能少
- {n,m}?重复n到m次,但尽可能少
- {n,}?重复n次以上,但尽可能少
分支条件
和或逻辑比较像,匹配到了第一个就不继续匹配了
0\d{2}-\d{8}0\d{3}-\d{7}
这个表达式可以匹配两种电话号码:一种是三位区号,8位本地号(如010-12345678),一种是4位区号,7位本地号(0376-2233445)
\d{5}-\d{4}|\d{5}
这个表达式用于匹配美国的邮政编码。美国邮编的规则是5位数字,或者用连字号间隔的9位数字。但是要注意,如果改掉两个匹配类型的顺序,那么最后的结果会改变。
\d{5}|\d{5}-\d{4}
的意思的是匹配到
因此:使用分枝条件时,要注意各个条件的顺序
分组
重复单个字符是字符后加上限定符;如果想重复多个字符,可以用小括号来指定子表达式,也叫做分组.
举例:ip地址匹配
/(\d{1,3}\.){3}\d{1,3}/
这是个简单的ip地址匹配,但是会匹配到不存在的ip地址,如果要没有缺陷,那么必须弄一个长长的正则表达式
/(2[0-4]\d|25[0-5]|[01]?\d{2}\.){3}2[0-4]\d|25[0-5]|[01]?\d{2}/
后向引用
直接看例子吧,直接看概念估计是不会懂的
/\b(\w+)\b\s+\1\b/
- 匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。默认情况下,每个分组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一个出现的分组组号为1,第二个为2,以此类推。因此上述正则表达式分析如下:单词开始处和结束处之间的多于一个的字母或数字(\b(\w+)\b),这个单词会被捕获到编号为1的分组中,然后是1个或几个空白符(\s+),最后是分组1中捕获的内容(也就是前面匹配的那个单词)(\1)
- 也可以自己指定表达式的组名,语法是这样的:
(?<Word>\w+)
或者(?'Word'\w+)
这样就把\w+的组名指定为Word了。反向引用时:
\b(?<Word>\w+)\b\s+\k<Word>\b
零宽断言
拿例子来说话:
- 零宽度正预测先行断言(?=exp):断言自身出现的位置的后面能匹配表达式exp。比如
/\b\w+(?=ing\b)/
用来匹配ing结尾的单词的前面部分。比如查找I'm singing while you're dancing.时,它会匹配sing和danc. - 零宽度正回顾后发断言(?<=exp):断言自身出现的位置前面能出现exp.比如
/(?<=\bre)\w+\b/
可以匹配re开头的单词的后半部分.例如查找reading a book,会匹配到ading.
注释
小括号的另一种用途时用语法(?#comment)来包含注释。
2[0-4]\d(?#200-249)|25[0-5] (?#250-255)
tip:要包含注释的话,最耗时启用"忽略模式里的空白符",这样编写表达式时可以任意添加空格,TAB,换行,实际使用时这些会被忽略。启用这一选项后,在#后面到这一行结束的所有文本都将被注释掉:
(?<= # 断言要匹配的文本的前缀
<(\w+)> # 查找尖括号括起来的字母或数字(即HTML/XML标签)
) # 前缀结束
.* # 匹配任意文本
(?= # 断言要匹配的文本的后缀
<\/\1> # 查找尖括号括起来的内容:前面是一个"/",后面是先前捕获的标签
) # 后缀结束
emmm还有负向零宽断言,平衡组/递归匹配没讲到。。。下次补上
php查找所有的匹配结果
preg_match只能匹配一次结果,但很多时候我们需要匹配所有的结果,preg_match_all可以循环获取一个列表的匹配结果数组。
preg_matche_all($p,$str,$matches)是标准格式,匹配的结果保存到$matches里
看个例子:用preg_match_all匹配一个表格中的数据
$p = "/<tr><td>(.*?)<\/td>\s*<td>(.*?)<\/td>\s*<\/tr>/i";
$str = "<table> <tr><td>Eric</td><td>25</td></tr> <tr><td>John</td><td>26</td></tr> </table>";
preg_match_all($p, $str, $matches);
print_r($matches);
$matches结果排序$matches[0]保存完整模式的所有匹配。$matches[0]保存第一个子组的所有匹配,以此类推;
写一段代码测试一下
<?php
/**
* Created by PhpStorm.
* User: wanghao
* Date: 2018/1/2
* Time: 18:40
*/
$str="<ul>
<li>item 1</li>
<li>item 2</li>
</ul>";
$p="/<li>(.*)<\/li>/";
preg_match_all($p,$str,$matches);
print_r($matches);
得到的结果是:
Array
(
[0] => Array
(
[0] => <li>item 1</li>
[1] => <li>item 2</li>
)
[1] => Array
(
[0] => item 1
[1] => item 2
)
)
正则表达式的搜索和替换
正则表达式的搜索与替换在某些方面具有重要用途,比如调整目标字符串的格式,改变目标字符串中匹配字符串的顺序等。
标准用法:preg_replace($pattern,$replacement,$str);返回值即是调整后的结果。
例子:调整字符串的日期格式
$string = 'April 15, 2014';
$pattern = '/(\w+) (\d+), (\d+)/i';
$replacement = '$3, ${1} $2';
echo preg_replace($pattern, $replacement, $string); //结果为:2014, April 15
这里${1}和$1的写法是等价的,表示第一个匹配的串,$2表示的是第二个匹配的串,以此类推。
tip:可以看到,这里的匹配到的串都是用小括号括起来的部分的内容,即分组对应到这里的匹配串。
例子:用正则表达式去掉多余的空格
$str = 'one two';
$str = preg_replace('/\s+/',' ',$str);
echo $str;//结果就变成了'one two'
正则匹配常用例子
正则匹配常用在表单验证上,一些字段会有一定的格式要求,比如用户名一般都要求必须是字母、数字或下划线组成,邮箱、电话等也都有自己的规则,因此使用正则表达式可以很好的对这些字段进行验证
看一个用户注册页的例子,对各字段进行验证:
<?php
$user = array(
'name' => 'spark1985',
'email' => 'spark@imooc.com',
'mobile' => '13312345678'
);
//进行一般性验证
if (empty($user)) {
die('用户信息不能为空');
}
if (strlen($user['name']) < 6) {
die('用户名长度最少为6位');
}
//用户名必须为字母、数字与下划线
if (!preg_match('/^\w+$/i', $user['name'])) {
die('用户名不合法');
}
//验证邮箱格式是否正确
if (!preg_match('/^[\w\.]+@\w+\.\w+$/i', $user['email'])) {
die('邮箱不合法');
}
//手机号必须为11位数字,且为1开头
if (!preg_match('/^1\d{10}$/i', $user['mobile'])) {
die('手机号不合法');
}
echo '用户信息验证成功';
未完待续