【PHP小课堂】PHP中PRGE正则函数的学习

PHP中PRGE正则函数的学习

正则表达式的作用想必不用我多说了,大家在日常的开发中或多或少都会接触到。特别是对于一些登录(邮箱、手机号)以及网页爬虫来说,正则表达式就是神器一般的存在。在 PHP 中,有两种处理正则表达式的函数,今天我们就来学习其中的一种。

PCRE 与 POSIX

前面说到,有两种处理正则的函数库,一个是 POSIX 为主的 ereg_xxx 这种函数,不过它们已经被淘汰了,并不是很推荐使用。而另一种就是基于 PCRE 的以 preg_xxx 开头的这种函数库。今天我们主要学习的就是这类型的正则处理函数库。

POSIX 类型的正则函数库不是二进制安全的,并且对 utf8 的支持也不好,所以从 PHP5.3 开始如果使用 ereg_xxx 这类的函数就会报一个 E_DEPRECATED 错误。PCRE 的函数库对 perl 支持非常友好,同时,它也是支持 POSIX 扩展语法的正则表达式。具体的正则语法规则和模式修饰符相关的信息可以在文末的链接中查阅。关于模式修饰符的作用这里就不多说了,不清楚的小伙伴自己查找相关的资料哦。

另外,PCRE 与 POSIX 和 perl 也是有一些不同的,这些内容也都在文末的官方文档链接中可以看到。

正则匹配

好了,话不多说,我们直接进入主题,其实大部分内容相信不少同学都是接触过的,我们就来一一演示学习一下。

$str = "a@qq.com,b@sina.COM,c@yahoo.com,一堆测试数据。Test Txt.";preg_match_all("/(.*)@(.*)\.(.*),/iU", $str, $out);
print_r($out);
// Array
// (
//     [0] => Array
//         (
//             [0] => a@qq.com,
//             [1] => b@sina.com,
//             [2] => c@yahoo.com,
//         )//     [1] => Array
//         (
//             [0] => a
//             [1] => b
//             [2] => c
//         )//     [2] => Array
//         (
//             [0] => qq
//             [1] => sina
//             [2] => yahoo
//         )//     [3] => Array
//         (
//             [0] => com
//             [1] => com
//             [2] => com
//         )// )preg_match_all("/(.*)@(.*)\.(.*),/iU", $str, $out, PREG_SET_ORDER);
print_r($out);
// Array
// (
//     [0] => Array
//         (
//             [0] => a@qq.com,
//             [1] => a
//             [2] => qq
//             [3] => com
//         )//     [1] => Array
//         (
//             [0] => b@sina.COM,
//             [1] => b
//             [2] => sina
//             [3] => COM
//         )//     [2] => Array
//         (
//             [0] => c@yahoo.com,
//             [1] => c
//             [2] => yahoo
//             [3] => com
//         )// )preg_match_all("/(.*)@(.*)\.(.*),/iU", $str, $out, PREG_OFFSET_CAPTURE);
print_r($out);
// Array
// (
//     [0] => Array
//         (
//             [0] => Array
//                 (
//                     [0] => a@qq.com,
//                     [1] => 0
//                 )//             [1] => Array
//                 (
//                     [0] => b@sina.COM,
//                     [1] => 9
//                 )//             [2] => Array
//                 (
//                     [0] => c@yahoo.com,
//                     [1] => 20
//                 )//         )//     [1] => Array
//         (
//             [0] => Array
//                 (
//                     [0] => a
//                     [1] => 0
//                 )//             [1] => Array
//                 (
//                     [0] => b
//                     [1] => 9
//                 )//             [2] => Array
//                 (
//                     [0] => c
//                     [1] => 20
//                 )//         )//     [2] => Array
//         (
//             [0] => Array
//                 (
//                     [0] => qq
//                     [1] => 2
//                 )//             [1] => Array
//                 (
//                     [0] => sina
//                     [1] => 11
//                 )//             [2] => Array
//                 (
//                     [0] => yahoo
//                     [1] => 22
//                 )//         )//     [3] => Array
//         (
//             [0] => Array
//                 (
//                     [0] => com
//                     [1] => 5
//                 )//             [1] => Array
//                 (
//                     [0] => COM
//                     [1] => 16
//                 )//             [2] => Array
//                 (
//                     [0] => com
//                     [1] => 28
//                 )//         )// )

preg_match_all() 函数用于完全的匹配,也就是文本中的内容全都匹配出来,并且将结果放到一个引用数组中。注意它最后的那个可选参数,默认情况下,数组的 0 下标是所有匹配到的字符内容,而剩下的索引内容是括号内部匹配的结果,可以对应到后面我们学习的替换函数中的 $1$2 这些插值中。

如果将最后一个参数设置为 PREG_SET_ORDER ,那么数据会以分组的形式展示,一级数组中就是每一个匹配到的内容,二级数组的 0 下标就是这个完全的文本内容,而后面的数据就是对应于这个完全匹配内容的括号内部匹配数据。

设置为 PREG_OFFSET_CAPTURE 的话,在格式上其实和默认情况下是一样的,只是每个数组内部又多了一个表示匹配位置的数字下标值。

说实话,这三个属性原来还真的没有了解过,很多时候需要这些功能的时候反而是自己又重新去写算法进行操作,这下也算是开了眼界。

preg_match("/(.*)@(.*)\.(.*),/iU", $str, $out);
print_r($out);
// Array
// (
//     [0] => a@qq.com,
//     [1] => a
//     [2] => qq
//     [3] => com
// )preg_match("/(.*)@(.*)\.(.*),/iU", $str, $out, PREG_OFFSET_CAPTURE, 2);
print_r($out);
// Array
// (
//     [0] => Array
//         (
//             [0] => qq.com,b@sina.COM,
//             [1] => 2
//         )//     [1] => Array
//         (
//             [0] => qq.com,b
//             [1] => 2
//         )//     [2] => Array
//         (
//             [0] => sina
//             [1] => 11
//         )//     [3] => Array
//         (
//             [0] => COM
//             [1] => 16
//         )// )

preg_match() 函数就比较简单了,它只返回第一个与正则相匹配的数据。当然,它也有一些可选的参数。最后一个可选参数的作用就是偏移量,我们从第 2 个字符以后开始匹配,这里匹配到的数据和第一条中的就不一样了。

字符串分割

就像 explode() 和 str_split() 函数一样,正则中也有将字符串分割为数组的函数,它一般会作用于更复杂的分割条件。

print_r(preg_split("/@(.*)\.(.*),/iU", $str));
// Array
// (
//     [0] => a
//     [1] => b
//     [2] => c
//     [3] => 一堆测试数据。Test Txt.
// )print_r(preg_split("/@(.*)\.(.*),/iU", $str, 2, PREG_SPLIT_OFFSET_CAPTURE));
// Array
// (
//     [0] => Array
//         (
//             [0] => a
//             [1] => 0
//         )//     [1] => Array
//         (
//             [0] => b@sina.COM,c@yahoo.com,一堆测试数据。Test Txt.
//             [1] => 9
//         )// )

这里我们是通过 @xxx.xxx, 来作为分隔符,所以分隔后的结果就是不包含这个分隔符的数组数据。preg_split() 这个函数的默认使用也是比较简单的,它同样有一些可选参数,比如第二条,第三个可选参数的作用是限制分割的数量,这里我们限制只分割成两个数组,所以文本后面的内容都会放到一个数组中,并且通过最后一个参数来指定返回查找到的数据的位置在字符串中的下标。

正则替换

关于替换的内容就比较多了,可以说,除了第一个我们介绍的 preg_match_all() 之外,最常用的就是 preg_replace() 这个函数了。它的作用当然也是和 str_replace() 类似的,只不过使用正则的话条件能够更丰富,也更加强大。

普通替换

echo preg_replace("/@(.*)\.(.*),/iU", '@$1.$2.cn, ',$str), PHP_EOL;
// a@qq.com.cn, b@sina.COM.cn, c@yahoo.com.cn, 一堆测试数据。Test Txt.echo preg_replace("/[\x{4E00}-\x{9FFF}]+/u", 'Many Test Info.',$str, -1, $count), PHP_EOL;
echo $count, PHP_EOL;
// a@qq.com,b@sina.COM,c@yahoo.com,Many Test Info.。Test Txt.
// 3echo preg_replace("/@(.*)\.(.*),/iU", '@$1.$2.cn, ',$str, 2, $count), PHP_EOL;
echo $count, PHP_EOL;
// a@qq.com.cn, b@sina.COM.cn, c@yahoo.com,一堆测试数据。Test Txt.
// 2

普通的 preg_replace() 函数也是非常简单的,它的可选参数其实和 str_replace() 也是类似的,第 4 个参数指定替换数量,比如第二条设置为 -1 也就是默认值,这样就是全部替换,而第三条就是设置为 2 ,只会替换两条匹配的内容。最后一个参数是返回匹配替换的数量,它是一个引用参数,也就是文本中我们一共替换掉了多少内容,或者说是我们匹配到了多少条信息。

另外还有一个函数和 preg_replace() 非常类似。我们直接来看它和 preg_replace() 的区别。

echo preg_filter("/@(.*)\.(.*),/iU", '@$1.$2.cn, ',$subStr), PHP_EOL;$subject = array('1', 'a', '2', 'b', '3', 'A', 'B', '4'); 
$pattern = array('/\d/', '/[a-z]/', '/[1a]/'); 
$replace = array('A:$0', 'B:$0', 'C:$0'); echo "preg_filter 的结果:", PHP_EOL;
print_r(preg_filter($pattern, $replace, $subject)); 
// preg_filter 的结果:
// Array
// (
//     [0] => A:C:1
//     [1] => B:C:a
//     [2] => A:2
//     [3] => B:b
//     [4] => A:3
//     [7] => A:4
// )echo "preg_replace 的结果:", PHP_EOL;
print_r(preg_replace($pattern, $replace, $subject));
// preg_replace 的结果:
// Array
// (
//     [0] => A:C:1
//     [1] => B:C:a
//     [2] => A:2
//     [3] => B:b
//     [4] => A:3
//     [5] => A
//     [6] => B
//     [7] => A:4
// )

从上面的代码中可以看出,preg_filter() 函数最后返回的结果会是匹配到结果的内容,而 preg_replace() 如果字符中没有匹配到结果,也会返回原始的内容。它们两个的参数是完全相同的。

在这段测试代码中,我们使用了数组作为替换的前三个参数,它们的匹配规则是 pattern 对应 replace 的一个一个去匹配。也就是说,0 号下标的 /\d/ 对应的匹配规则是 A:$0 ,如果缺少了替换或者匹配规则的话,不会报错,但替换的结果可能就不是你想要的了。

注意,只有替换类的函数是可以这样接收数组作为参数的。

回调替换

除了上面的替换之外,PRGE 的函数库中还有回调式替换的函数,也就是能让我们自定义替换之后的返回结果。

print_r(preg_replace_callback($pattern, function($matches){print_r($matches);return strtolower($matches[0]);
}, $subject));
// Array
// (
//     [0] => 1
// )
// Array
// (
//     [0] => 1
// )
// Array
// (
//     [0] => a
// )
// Array
// (
//     [0] => a
// )
// Array
// (
//     [0] => 2
// )
// Array
// (
//     [0] => b
// )
// Array
// (
//     [0] => 3
// )
// Array
// (
//     [0] => 4
// )
// Array
// (
//     [0] => 1
//     [1] => a
//     [2] => 2
//     [3] => b
//     [4] => 3
//     [5] => A
//     [6] => B
//     [7] => 4
// )print_r(preg_replace_callback('/(.*)@(.*)\.(.*),/iU', function($matches){return strtoupper($matches[0]);
}, $str));
// A@QQ.COM,B@SINA.COM,C@YAHOO.COM,一堆测试数据。Test Txt.

preg_replace_callback() 的第二个参数其实就是相当于把 preg_replace() 中的替换字符串换成一个匿名回调函数了。这个函数中的参数就是匹配到的结果,上面的测试代码中我们全部打印了出来。然后给这个函数一个 return 返回值,就是对应地去把替换的结果返回到原值中。

preg_replace_callback() 最终的返回值是根据传递给它的原始数据来确定的,如果是数组就返回数组,如果是字符串就返回的字符串。

另外还有一种更复杂的回调函数。

print_r(preg_replace_callback_array(['/(.*)@(.*)\.(.*),/iU' => function ($matches) {echo 'one:', $matches[0], PHP_EOL;return strtoupper($matches[0]);},'/Test Txt./iU' => function ($matches) {echo 'two:', $matches[0], PHP_EOL;return strtoupper($matches[0]);}],$str
));
// one:a@qq.com,
// one:b@sina.COM,
// one:c@yahoo.com,
// two:Test Txt.
// A@QQ.COM,B@SINA.COM,C@YAHOO.COM,一堆测试数据。TEST TXT.

没错,在一个函数中进行两种正则模式的匹配。是不是感觉很高大上。这个函数的使用场景就不多了,而且需要注意的是,如果第一条正则匹配到数据了,第二条正则就不会有匹配的结果了,这个大家可以自己测试一下。

匹配验证及字符串模式格式转换

匹配验证就是验证我们的正则表达式是否能匹配到的内容。

print_r(preg_grep("/\d/", [$str]));
// Array
// (
// )print_r(preg_grep("/\d/", [$str], PREG_GREP_INVERT));
// Array
// (
//     [0] => a@qq.com,b@sina.COM,c@yahoo.com,一堆测试数据。Test Txt.
// )

它只返回能够匹配到的数据,也就是第二个参数。这个参数必须是一个数组,可以验证多条数据是否能够通过这个正则匹配到内容,但不返回具体的匹配内容信息。可以用作在正式的 preg_match_all() 或者替换、分割操作之前的判断验证。它的最后一个参数如果设置为 PREG_GREP_INVERT 的话,就是反向地获取不能和正则匹配的数据。

print_r(preg_quote("(.*).(.*),"));
// \(\.\*\)\.\(\.\*\),

preg_quote() 函数其实是有点类似于 addslashes() 函数,它是针对正则中的特殊符号添加转义斜杠的。

错误信息

最后我们再看看错误信息的展示,对于正则匹配的错误,在 PHP8 之前仅有一个错误号,作用不大。

preg_match("///", $str);print_r(preg_last_error()); 
// Warning: preg_match(): Delimiter must not be alphanumeric or backslash in /Users/zhangyue/MyDoc/博客文章/dev-blog/php/2021/03/source/6.PHP中PRGE正则函数的学习.php on line 332
// 1
// print_r(preg_last_error_msg());  // php8

而在 PHP8 之后,新增加了一个 preg_last_error_msg() 可以返回错误信息。不过我的电脑上还没有安装 PHP8 所以这块内容就不展示了。

总结

PHP 中正则操作的函数就这些,但正则真正的精髓其实是在于正则表达式怎么写这一块。不好的正则可能会产生严重的回溯导致性能的急剧下降,所以在做业务开发的时候,能不用正则其实还是尽量不要用的。不过相对来说,像是登录的用户验证之类的功能,正则简直不要太好用,这个就完全可以让正则好好发挥啦!另外,用好模式修饰符也是能够有效地提升正则效率的,这些都是值得我们深入去研究的东西,有兴趣的小伙伴多多阅读官方文档,一定能找到让你惊喜的地方。

测试代码:

https://github.com/zhangyue0503/dev-blog/blob/master/php/2021/03/source/6.PHP%E4%B8%ADPRGE%E6%AD%A3%E5%88%99%E5%87%BD%E6%95%B0%E7%9A%84%E5%AD%A6%E4%B9%A0.php

参考文档:

https://www.php.net/manual/zh/book.pcre.php

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/35890.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ChatGPT在用户交互过程中如何实现自我学习和优化?

ChatGPT的自我学习和优化:深度解析与未来展望 在人工智能领域,ChatGPT的出现标志着自然语言处理技术的一大飞跃。作为一个先进的语言模型,ChatGPT不仅能够与用户进行流畅的对话,还能够通过自我学习和优化来不断提升其性能。本文将…

【SkiaSharp绘图11】SKCanvas属性详解

文章目录 SKCanvas构造SKCanvas构造光栅 Surface构造GPU Surface构造PDF文档构造XPS文档构造SVG文档SKNoDrawCanvas 变换剪裁和状态构造函数相关属性DeviceClipBounds获取裁切边界(设备坐标系)ClipRect修改裁切区域IsClipEmpty当前裁切区域是否为空IsClipRect裁切区域是否为矩形…

JFreeChart 生成Word图表

文章目录 1 思路1.1 概述1.2 支持的图表类型1.3 特性 2 准备模板3 导入依赖4 图表生成工具类 ChartWithChineseExample步骤 1: 准备字体文件步骤 2: 注册字体到FontFactory步骤 3: 设置图表具体位置的字体柱状图:饼图:折线图:完整代码&#x…

【QT】Svg图标

目录 SVGQT绘制SVG流程 SVG 一般而言,QSS是无法直接使用svg图像的。 那如何才能显示svg呢?我们知道svg的好处有很多,如矢量图,体积小等等 svg本来就是一个document(可参考12),QT提供了QSvgRend…

二叉树深度优先搜索(非递归实现,迭代法)

目录 为什么可以用迭代法实现二叉树的前后中序遍历? 前序遍历 后序遍历 中序遍历 为什么可以用迭代法实现二叉树的前后中序遍历? 因为递归的实现本质是,每次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然…

web期末作业设计网页

设计一个网页作为期末作业是一个很好的机会来展示你的前端开发技能。以下是一些步骤和建议,帮助你完成这个项目: 1. 确定网页主题和目的 决定你的网页是关于什么的(例如:个人博客、在线商店、公司网站、信息发布平台等&#xff…

国产车规MCU OTA方案总结

目录 1. 旗芯微FC4150 OTA 2. 云途YTM32B1MD OTA 3.小结 今天没有废话,啪一下很快,把目前接触到的国内带eFlash的车规MCU硬件OTA方案做一个梳理。 1. 旗芯微FC4150 OTA 旗芯微FC4150是基于ARM Cortex(快去审核下官网介绍,少了个T)-M4F内…

入门者必看-Ansible:自动化运维的利器

1. 引言 在当今快速变化的IT环境中,自动化成为了提升工作效率和确保系统一致性的重要手段。Ansible作为一个开源的自动化工具,因其简单易用、功能强大而广受欢迎。本文将深入探讨Ansible的概念、架构、体系结构、搭建过程、常用操作方式以及使用场景&…

openGauss Developer Day 2024丨MogDB实现数据库技术跨越,Ustore引擎革新存储新境界

openGauss Developer Day 2024 6月21日,openGauss Developer Day 2024在北京昆泰嘉瑞文化中心成功召开。大会聚集学术专家、行业用户、合作伙伴和开发者,共同探讨数据库面向多场景的技术创新,分享基于 openGauss 的行业联合创新成果及实践案例…

探索PHP中的魔术常量

PHP中的魔术常量(Magic Constants)是一些特殊的预定义常量,它们在不同的上下文中具有不同的值。这些常量可以帮助开发者获取文件路径、行号、函数名等信息,从而方便调试和日志记录。本文将详细介绍PHP中的魔术常量,帮助…

web前端——javaScript

目录 一、javaScript概述 1.javaScript历史 2.JavaScript与html,css关系 二、基本语法 ①放在head中 ②放在 body中 ③写在外部的.js文件中 1.变量 2.数据类型 3.算术运算符 4.逻辑运算符 5.赋值运算 6.逻辑运算符 7.条件运算符 8.控制语句 三、函数 1…

智能扫地机器人环境感知与地图构建优化方案

以下是一个针对智能扫地机器人程序中环境感知与地图构建问题的具体解决方案,参考了之前文章中的相关技术和信息: 智能扫地机器人环境感知与地图构建优化方案 一、引入高精度传感器 激光雷达(LiDAR):使用高精度激光雷达…

模板语法轮播

1.常用的视图容器组件 view类似于div进行使用 <div></div><view></view> scroll-view实现滚动列表效果 <scroll-view scroll-y> <view></view> <view></view> <view></view> </scroll-view> …

数据库死锁解决

一、Oracle死锁查看和解决办法汇总 由于生产的tomcat 经常有假死问题&#xff0c;困扰很久&#xff0c;最后发现有死锁&#xff0c;解决办法分享 1.1、查看死锁 1.1.1、用dba用户执行以下语句 select username,lockwait,status,machine,program from v$session where sid in …

Arduino - 按钮 - 长按短按

Arduino - Button - Long Press Short Press Arduino - 按钮 - 长按短按 Arduino - Button - Long Press Short Press We will learn: 我们将学习&#xff1a; How to detect the button’s short press 如何检测按钮的短按How to detect the button’s long press 如何检测…

重大进展!微信支付收款码全场景接入银联网络

据中国银联6月19日消息&#xff0c;近日&#xff0c;银联网络迎来微信支付收款码场景的全面接入&#xff0c;推动条码支付互联互通取得新进展&#xff0c;为境内外广大消费者提供更多支付选择、更好支付体验。 2024年6月&#xff0c;伴随微信支付经营收款码的开放&#xff0c;微…

Docker部署Nginx+Keepalived

# 创建挂载路径 mkdir /data/nginx_keep/nginx/conf -p mkdir /data/nginx_keep/keepalived/vim nginx.conf user nginx; worker_processes auto;error_log /var/log/nginx/error.log notice; pid /var/run/nginx.pid;events {worker_connections 1024; }http {incl…

Rust: duckdb和polars读csv文件比较

一、文件准备 样本内容&#xff0c;N行9列的csv标准格式&#xff0c;有字符串&#xff0c;有浮点数&#xff0c;有整型。 有两个csv文件&#xff0c;一个大约是2.1万行&#xff1b;一个是64万行。 二、toml文件 [package] name "my_duckdb" version "0.1.0&…

opencv简单小项目

OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源的计算机视觉和机器学习软件库&#xff0c;它提供了大量的图像和视频处理功能。使用OpenCV可以开发各种简单的小项目&#xff0c;例如&#xff1a; 图像基本操作&#xff1a; 读取和显示图像。调整…

弱监督学习

弱监督学习&#xff08;Weak Supervision&#xff09;是一种利用不完全、不精确或噪声数据进行模型训练的方法。以下是一些常用的弱监督方法及其原理&#xff1a; 1. 数据增强&#xff08;Data Augmentation&#xff09; 原理&#xff1a; 数据增强是一种通过增加训练数据的多…