PHP中的正则表达式实例详解


Posted in PHP onApril 25, 2017

最近使用 PHP 写了一个应用,主要是正则表达式的处理,趁机系统性的学习了相应知识。
这篇文章的写作方式不是讲理论,而是通过具体的例子来了解正则,这样也更有实践性,在此基础上再去看正则表达式的基本概念会更有收获。

禁止分组的捕获

在正则中分组很有用,可以定义子模式,然后可以通过后向引用来引用分组的内容,但是有的时候仅仅想通过分组来进行范围定义,而不想被分组来捕获,通过一个例子就能明白:

$str = "http://www.google.com";
$preg= "/http:\/\/\w+\.\w+.(?:net|com|cn)+/is";
$preg2= "/http:\/\/\w+\.\w+.(net|com|cn)+/is";
preg_match($preg,$str,$arr);
preg_match($preg2,$str,$arr2);

当模式中出现?:表示这个括号的分组不会被引用,运行下例子就能明白。

preg_match() 和 preg_match_all() 的区别

preg_match() 在匹配模式的时候匹配到一次就结束,而 preg_match_all() 则进行全局匹配,通过一个例子就能明白:

$str='hello world china';
$preg="/\w+\s/is";
preg_match($preg,$str,$arr);
print_r($arr);
preg_match_all($preg,$str,$arr);
print_r($arr);

正确理解 $ 和 ^

先说一个正则,为了匹配是否是手机号:

$str = "13521899942a";
$preg="/1[\d]{3,15}/is";
if (preg_match($preg,$str,$arr)) {
  echo "ok";
}

虽然字符串中有一个英文字母,但是这个子模式却匹配了,原因就在于模式匹配到后就结束了,不会再去寻找英文字母,为了解决这问题 $ 和 ^ 就发挥作用了,比如让字符串的开始和结尾必须匹配一定的模式,修改如下:

$str = "13521899942a";
$preg="/1[\d]{3,15}$/is";
if (preg_match($preg,$str,$arr)) {
  echo "ok";
}

$ 和 ^ 的跨行模式

默认的情况下,$ 和 ^ 只会匹配完整段落的开始和结尾,但是通过改变选项,允许匹配文本的每一行的开始和结尾,通过下面的例子就能明白

$str='hello
world';
$preg='/\w+$/ism';//$preg='/(?m)\w+$/is';
preg_match_all($preg,$str,$arr);
print_r($arr);

分组命名

在正则中通过括号分组后,可以使用 \1,\2 这样的数字进行后向引用,但是假如正则中模式太多,在使用的时候就会比较混乱,这时候可以采用分组命名来进行引用,看个例子:

$str ="email:ywdblog@gmail.com;";
preg_match("/email:(?<email>\w+?)/is", $str, $matches);
echo $matches["email"] . "_" . $matches['no'];

懒惰模式

正则在匹配的时候是贪婪的,只要符合模式就会一直匹配下去,下面的例子,匹配到的文本是 <h2>hello</h2><h2>world</h2>

$str = "<h2>hello</h2><h2>world</h2>";
$preg = "/<h2>.*<\/h2>/is";
preg_match($preg,$str,$arr);
print_r($arr);

通过改变一个选项可以修改为懒惰模式,就是一旦匹配到就中止,修改代码如下:

$str = "<h2>hello</h2><h2>world</h2>";
$preg = "/<h2>.*?<\/h2>/is";
preg_match($preg,$str,$arr);
print_r($arr);

进一步理解 preg_match_all()

通过这函数的最后一个参数,能够返回不同形式的数组:

$str= 'jiangsu (nanjing) nantong
guangdong (guangzhou) zhuhai
beijing (tongzhou) haidian';
$preg = '/^\s*+([^(]+?)\s\(([^)]+)\)\s+(.*)$/m';
preg_match_all($preg,$str,$arr,PREG_PATTERN_ORDER);
print_r($arr);
preg_match_all($preg,$str,$arr,PREG_SET_ORDER);
print_r($arr);

强大的正则替换回调

虽然 preg_replace() 函数能完成大多数的替换,但是假如你想更好的控制,可以使用回调,不用多说看例子:

$str = "china hello world";
$preg = '/\b(\w+)(\w)\b/';
function fun($m){
    return $m[1].strtoupper($m[2]);
}
echo preg_replace_callback($preg,"fun",$str);

在这一点上,PHP 比 Python 强大的多,Python 中没有正则回调,不过可以使用闭包的方式解决,可看我以前的文章。

preg_quote()

这个函数类似于 Python 中的 re.compile() 函数,假如在模式中一些元字符仅仅想表达字符的本身含义,可以转义,但是假如在模式中写太多的转义,会显得很混乱,可以使用这个函数来统一转义:

$str = '\\*china*world';
$preg = "\*china";
$preg = preg_quote($preg);
echo $preg;
preg_match( "/{$preg}/is",$str,$arr);
print_r($arr);

向前查找 ?= 的妙用

用英文解释可能比较贴切:

The "?=" combination means "the next text must be like this". This construct doesn't capture the text.
(1)这个例子可以获取 URL 中的协议部分,比如 https,ftp,注意 ?: 后面的部分不在返回的内容中。

$str = "http://www.google.com";
$str = "https://www.google.com";
$preg = '/[a-z]+(?=:)/';
preg_match($preg,$str,$arr);
print_r($arr);

(2)"invisible" 分隔符

也叫 “zero-width” 分隔符,参考下面的例子:

$str = ("chinaWorldHello");
$preg = "/(?=[A-Z])/";
$arr = preg_split($preg,$str);
print_r($arr);

(3)匹配强密码

instead of specifying the order that things should appear, it's saying that it must appear but we're not worried about the order.
The first grouping is (?=.{8,}). This checks if there are at least 8 characters in the string. The next grouping (?=.[0-9]) means "any alphanumeric character can happen zero or more times, then any digit can happen". So this checks if there is at least one number in the string. But since the string isn't captured, that one digit can appear anywhere in the string. The next groupings (?=.[a-z]) and (?=.[A-Z]) are looking for the lower case and upper case letter accordingly anywhere in the string.

$str= "HelloWorld2016";
if (preg_match("/^.*(?=.{8,})(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).*$/", $str,$arr)){
  print_r($arr);
}

向后查找 ?<=

?<= 表示假如匹配到特定字符,则返回该字符后面的内容。
?= 表示假如匹配到特定字符,则返回该字符前面的内容。

$str = 'chinadhello';
$preg = '/(?<=a)d(?=h)/';  
preg_match($preg, $str, $arr);
print_r($arr);

好了,今天的教程就先到这里,有什么问题大家可以留言,我们来讨论下

PHP 相关文章推荐
PHP 开源框架22个简单简介
Aug 24 PHP
改写函数实现PHP二维/三维数组转字符串
Sep 13 PHP
php获取汉字首字母的函数
Nov 07 PHP
php实现保存submit内容之后禁止刷新
Mar 19 PHP
php通过隐藏表单控件获取到前两个页面的url
Sep 09 PHP
微信公众号点击菜单即可打开并登录微站的实现方法
Nov 14 PHP
PHP 正则表达式小结
Feb 12 PHP
php使用pdo连接sqlite3的配置示例
May 27 PHP
php基于curl实现随机ip地址抓取内容的方法
Oct 11 PHP
php简单随机字符串生成方法示例
Apr 19 PHP
Yii2语言国际化自动配置详解
Aug 22 PHP
php更新cookie内容的详细方法
Sep 30 PHP
PHP利用二叉堆实现TopK-算法的方法详解
Apr 24 #PHP
关于PHP定时发送服务的解决办法
Apr 23 #PHP
php读取和保存base64编码的图片内容
Apr 22 #PHP
PHP7多线程搭建教程
Apr 21 #PHP
mac系统下安装多个php并自由切换的方法详解
Apr 21 #PHP
php获取excel文件数据
Apr 21 #PHP
PHP实现限制IP访问的方法
Apr 20 #PHP
You might like
php绘图之生成饼状图的方法
2015/01/24 PHP
JavaScript中继承的一些示例方法与属性参考
2010/08/07 Javascript
Jquery.LazyLoad.js修正版下载,实现图片延迟加载插件
2011/03/12 Javascript
JQuery实现当鼠标停留在某区域3秒后自动执行
2014/09/09 Javascript
jquery.cookie.js使用指南
2015/01/05 Javascript
javascript实现在网页任意处点左键弹出隐藏菜单的方法
2015/05/13 Javascript
百度地图给map添加右键菜单(判断是否为marker)
2016/03/04 Javascript
javascript对象的创建和访问
2016/03/08 Javascript
jquery判断iPhone、Android设备类型
2016/09/14 Javascript
基于layui数据表格以及传数据的方式
2018/08/19 Javascript
JS原生带缩略图的图片切换效果
2018/10/10 Javascript
如何自动化部署项目?折腾服务器之旅~
2019/04/16 Javascript
vue中通过使用$attrs实现组件之间的数据传递功能
2019/09/01 Javascript
[03:20]次级联赛厮杀超职业 现超级兵对拆世纪大战
2014/10/30 DOTA
python直接访问私有属性的简单方法
2016/07/25 Python
python计算列表内各元素的个数实例
2018/06/29 Python
对Python中Iterator和Iterable的区别详解
2018/10/18 Python
Python爬取商家联系电话以及各种数据的方法
2018/11/10 Python
Python 实现微信防撤回功能
2019/04/29 Python
python使用time、datetime返回工作日列表实例代码
2019/05/09 Python
Django Rest framework认证组件详细用法
2019/07/25 Python
python FTP编程基础入门
2021/02/27 Python
浅谈css3中的渐进增强和优雅降级
2017/12/01 HTML / CSS
NFL墨西哥官方商店:Tienda NFL
2017/11/28 全球购物
命名空间(namespace)和程序集(Assembly)有什么区别
2015/09/25 面试题
求职信模版
2013/11/30 职场文书
自荐书模板
2013/12/19 职场文书
教师一岗双责责任书
2014/04/16 职场文书
财务工作疏忽检讨书
2014/09/11 职场文书
2014年国庆节演讲稿
2014/09/19 职场文书
学校捐书倡议书
2015/04/27 职场文书
心灵点滴观后感
2015/06/02 职场文书
学习焦裕禄先进事迹心得体会
2016/01/23 职场文书
工作总结之小学教师体育工作范文(3篇)
2019/10/07 职场文书
go goroutine 怎样进行错误处理
2021/07/16 Golang
MySQL 原理与优化之Update 优化
2022/08/14 MySQL