正则二三事 -- 正则基础 困扰多年的正则解析 正则进阶_^(foo1|foo2|baz)$-程序员宅基地

技术标签: php  

第一点正则表达式是什么呢?其实他就是一个工具,为了去匹配字符串,从而实现替换功能。

第二点正则表达式千万不要去背,要去理解它。这是关键。

总之 , 我们学习一个系统化的知识,一定要从其基础构成来了解。基础打牢,其他的一切都不是问题一点点抽丝剥茧。

同理  正则亦是如此,再复杂的正则也可以分解成简单正则从而一步一步掌握它所匹配的字符规则。

正则表达式的基本组成元素可以分为:字符和元字符

字符跟代码中的字符其实是一个意思代表一个字母一个数字,元字符比较特殊,他是特殊字符,例如 .  *   ? +  | ,有了这些元字符才能构造出强大的表达式模式

 

单个字符

一 一对应即单个字符的映射关系是一对一的,正则表达式被用来筛选匹配的字符只有一个, /a/ 就对应banner中的a,如果想匹配特殊字符的话  就要使用 “\”  它在正则中叫转义字符,例如 /\*/ 来匹配 appe*ll中的星号。其实“\”加上特殊字符   就是让特殊字符在正则中失去它本来的含义只配置这个字符本身而已。

但是如果转义字符“\”加上字符  那么它俩就会有着不同的含义 看下表:

含义 正则表达式 记忆方式
换行符 \n new line
换页符 \f form feed
回车符 \r return
空白符 \s space
制表符 \t tab
垂直制表符 \v vertical tab
回退符 [\b] backspace,之所以使用[]符号是避免和\b重复

多个字符:

单个字符是一对一映射的即只能匹配的字符只有一个,这不够呀,只要引入集合和通配符就能实现一对多了。

集合:使用 [ ] 来定义 既然是集合就要匹配这个集合里的一个或者两个元素例如/[123]/ 会匹配1或者2或者3 [1,2,3,4,5]也可以写成[1-5],以此类推 [0-9]就是匹配任意一个字符 [a-z]就是匹配任意一个字母

匹配区间 正则表达式 记忆方式
除了换行符之外的任何字符 . 句号,除了句子结束符
单个数字, [0-9] \d digit
除了[0-9] \D not digit
包括下划线在内的单个字符,[A-Za-z0-9_] \w word
非单字字符 \W not word
匹配空白字符,包括空格、制表符、换页符和换行符 \s space
匹配非空白字符 \S not space

循环重复 :

 一对一和 一对多都说完了  就下来就要说多对多了,其实只要多循环重复正则就行了  那么循环的次数可以分为 0 1 多次  特定次

特定次数是用{min,max} 来表示   

0|1      0次或1次      元字符  ?    例如color和colour  同时匹配到就可以使用/colou?r/

>=0     0次或多次    元字符   *  

>=1     一次或多次   元字符  +   

 .*?   代表的是任意尽量少的字符  ?代表的非贪婪模式 一般不会单独用大多是跟一个字母数组链接在一起/.*?a/取a前面任意长度的字符

位置边界

单词边界 /cat/ 能匹配到cat 和scatted  两种情况  那么久需要加上边界正则表达式 \b   /\bcat\b/ 就能匹配到cat单词了

字符串边界

元字符用^来表示字符串的开头   而使用$来表示字符串的末尾

边界和标志 正则表达式 记忆方式
单词边界 \b boundary
非单词边界 \B not boundary
字符串开头 ^ 头尖尖那么大个
字符串结尾 $ 终结者,美国科幻电影,美元符$
多行模式 m标志 multiple of lines      /    /m
忽略大小写 i标志 ignore case, case-insensitive    /     /i
全局模式 g标志 global      

 

子表达式:

字符匹配我们介绍的差不多了。更厉害的要来了,通过嵌套递归和引用本身可以发挥更加强大的功能

从简单到复杂的正则通常要采用分组,回溯引用,逻辑处理的思想 利用这个三种规则可以推演出无限循环的复杂正则

分组:

啥是分组呢:所有以()元字符所包含的正则表达式被分为一组,每一个分组都是一个子表达式,它是构成高级 正则表达式的基础,如果只使用简单匹配语法本质上和不分组是一样的,如果要发挥它的强大的作用  往往要结合回溯引用的方式。

回溯引用:

回溯引用指的是正则表达式后面的部分可以引用前面已经匹配到的字符串。你可以想象成变量,回溯引用的语法想\1,\2

其中\1表示的引用第一个子表达式 \2表示第二个表达式 \0表示整个表达式     \s是匹配到空格

假设现在要在下面这个文本匹配两个连续相同的单词

hello what what world is bealtuf all all shi 

利用回溯我就可以很快的写出  /\b(\w+)\s\1/     \s是表示空格\b是单词边界  \w是包括下划线的字符\1就是引用第一个子表达式

回溯引用在替换字符串中十分常用,语法上有些区别,这里来做一下标记 用$1,$2  ...以此类推来引用要被替换的字符串。

preg_replace('/(<img.+src=\"?.+)(images\/)(.+\.(jpg|gif|bmp|bnp|png)\"?.+>)/i',"\${1}uc/images/\${3}",$str); 

在匹配规则中要用\1 \2这种形式  而在preg_replace的替换字符中要用$1 $2

下面以js代码做一下演示吧

var str = "abc abc 123";
str.replace(/(ab)c/g,'$1g')      g是全局模式
// 得到的结果是 abg abg 123

如果我们不想子表达式被引用  可以使用非捕获正则(?regex)这样就可以避免浪费内存

var str = 'scq000'.
str.replace(/(scq00)(?:0)/, '$1,$2')
// 返回scq00,$2
// 由于使用了非捕获正则,所以第二个引用没有值,这里直接替换为$2

有时我们需要限制回溯引用的使用范围。那么通过前向查找和后向查找就可以达到这个目的

向前查找和向后查找通常是用来匹配文本,其目的是为了确定匹配结果的文本位置(通过指定匹配结果的前后必须是哪些文本)

前向查找是用来限制后缀的凡是以(?=regex)包含的子表达式在匹配的过程中都会用来限制前面的表达式的匹配,例如happy happily这两个词,我想以happ开头的副词那么就可以使用happ(?=ily)来匹配。如果我想过滤所有以happ来头的副词,那么也可以采用负前向查找的正则happ(?!ily),就会匹配到happy单词的happ前缀

介绍完前向查找,接着我们再来介绍一下它的反向操作:后向查找(lookbehind)。后向查找(lookbehind)是通过指定一个子表达式,然后从符合这个子表达式的位置出发开始查找符合规则的字串。举个简单的例子: applepeople都包含ple这个后缀,那么如果我只想找到appleple,该怎么做呢?我们可以通过限制app这个前缀,就能唯一确定ple这个单词了。

/(?<=app)ple/

其中(?<=regex)的语法就是我们这里要介绍的后向查找。regex指代的子表达式会作为限制项进行匹配,匹配到这个子表达式后,就会继续向查找。另外查找不同的是,一种限制匹配是利用(?<!regex) 语法,这里称为负后向查找。与正前向被指定的子表达式不能被匹配到。于是,在上面的例子中,如果想要查找appleple也可以这么写成/(?<!peo)ple

需要注意的,不是每种正则实现都支持后向查找。在javascript中是不支持的,所以如果有用到后向查找的情况,有一个思路是将字符串进行翻转,然后再使用前向查找,作完处理后再翻转回来。看一个简单的例子:

// 比如我想替换apple的ple为ply
var str = 'apple people';
str.split('').reverse().join('').replace(/elp(?=pa)/, 'ylp').split('').reverse().join('');
回溯查找 正则 记忆方式
引用 \0,\1,\2 和 $0, $1, $2 转义+数字    替换是用$1  $2  $3
非捕获组 (?:) 引用表达式(()), 本身不被消费(?),引用(:)
前向查找 (?=) 引用子表达式(()),本身不被消费(?), 正向的查找(=)
前向负查找 (?!) 引用子表达式(()),本身不被消费(?), 负向的查找(!)
后向查找 (?<=) 引用子表达式(()),本身不被消费(?), 后向的(<,开口往后),正的查找(=)
后向负查找 (?<!) 引用子表达式(()),本身不被消费(?), 后向的(<,开口往后),负的查找(!)

*1 PS:ES6标准之前的JavaScript不支持后查找,ES6开始支持

 

具体示例:

要求用正则取得字符串中圆括号内的子字符串.如字符串为we@13(HJGY@$)3lp,返回HJGY@$.

//正向前查找
foo(?=bar) //匹配后面带有bar的foo  向前去查找找foo
它可以匹配: foobar, abcfoobar fooabcbar中的foo
但是不能匹配:fooabc 中的foo

//正向后查找
(?<=foo)bar //匹配前面有foo的bar   
它可以匹配: foobar, 123foobar 中的bar
不可以匹配: 123bar 中的bar

//负向前查找:(?!)  负就是过滤了查找不到
foo(?!bar) //匹配后面不带bar的foo
它可以匹配: foo123
但是不能匹配:foobar

//负向后查找:(?< !)
(?< !foo)bar //匹配前面没有foo的bar
它可以匹配: 123bar 中的bar
不可以匹配: foobar, 123foobar 中的bar

//预查还可以嵌套 :
(?<=(?<!foo)bar)baz
匹配一个baz,它前面要有bar,但是bar的前面不可以是foo
它可以匹配 123barbaz 中的baz
但是不可以匹配foobarbaz

(?<=red)foo   red只是条件后向后查找foo   ()里面的只是查找的条件正如上面所说的  负就是过滤

var con="coming soon,going gogogo"
var reg = /\b[\w]+(?!=ing\b)/g;//匹配带ing的单词,但是不要ing。注意:如果ing后不加\b,类似于goingabc也会匹配。
console.log(con.match(reg));
//["com", "go"]

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/enjoy_sun_moon/article/details/103970744

智能推荐

攻防世界_难度8_happy_puzzle_攻防世界困难模式攻略图文-程序员宅基地

文章浏览阅读645次。这个肯定是末尾的IDAT了,因为IDAT必须要满了才会开始一下个IDAT,这个明显就是末尾的IDAT了。,对应下面的create_head()代码。,对应下面的create_tail()代码。不要考虑爆破,我已经试了一下,太多情况了。题目来源:UNCTF。_攻防世界困难模式攻略图文

达梦数据库的导出(备份)、导入_达梦数据库导入导出-程序员宅基地

文章浏览阅读2.9k次,点赞3次,收藏10次。偶尔会用到,记录、分享。1. 数据库导出1.1 切换到dmdba用户su - dmdba1.2 进入达梦数据库安装路径的bin目录,执行导库操作  导出语句:./dexp cwy_init/[email protected]:5236 file=cwy_init.dmp log=cwy_init_exp.log 注释:   cwy_init/init_123..._达梦数据库导入导出

js引入kindeditor富文本编辑器的使用_kindeditor.js-程序员宅基地

文章浏览阅读1.9k次。1. 在官网上下载KindEditor文件,可以删掉不需要要到的jsp,asp,asp.net和php文件夹。接着把文件夹放到项目文件目录下。2. 修改html文件,在页面引入js文件:<script type="text/javascript" src="./kindeditor/kindeditor-all.js"></script><script type="text/javascript" src="./kindeditor/lang/zh-CN.js"_kindeditor.js

STM32学习过程记录11——基于STM32G431CBU6硬件SPI+DMA的高效WS2812B控制方法-程序员宅基地

文章浏览阅读2.3k次,点赞6次,收藏14次。SPI的详情简介不必赘述。假设我们通过SPI发送0xAA,我们的数据线就会变为10101010,通过修改不同的内容,即可修改SPI中0和1的持续时间。比如0xF0即为前半周期为高电平,后半周期为低电平的状态。在SPI的通信模式中,CPHA配置会影响该实验,下图展示了不同采样位置的SPI时序图[1]。CPOL = 0,CPHA = 1:CLK空闲状态 = 低电平,数据在下降沿采样,并在上升沿移出CPOL = 0,CPHA = 0:CLK空闲状态 = 低电平,数据在上升沿采样,并在下降沿移出。_stm32g431cbu6

计算机网络-数据链路层_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏8次。数据链路层习题自测问题1.数据链路(即逻辑链路)与链路(即物理链路)有何区别?“电路接通了”与”数据链路接通了”的区别何在?2.数据链路层中的链路控制包括哪些功能?试讨论数据链路层做成可靠的链路层有哪些优点和缺点。3.网络适配器的作用是什么?网络适配器工作在哪一层?4.数据链路层的三个基本问题(帧定界、透明传输和差错检测)为什么都必须加以解决?5.如果在数据链路层不进行帧定界,会发生什么问题?6.PPP协议的主要特点是什么?为什么PPP不使用帧的编号?PPP适用于什么情况?为什么PPP协议不_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输

软件测试工程师移民加拿大_无证移民,未受过软件工程师的教育(第1部分)-程序员宅基地

文章浏览阅读587次。软件测试工程师移民加拿大 无证移民,未受过软件工程师的教育(第1部分) (Undocumented Immigrant With No Education to Software Engineer(Part 1))Before I start, I want you to please bear with me on the way I write, I have very little gen...

随便推点

Thinkpad X250 secure boot failed 启动失败问题解决_安装完系统提示secureboot failure-程序员宅基地

文章浏览阅读304次。Thinkpad X250笔记本电脑,装的是FreeBSD,进入BIOS修改虚拟化配置(其后可能是误设置了安全开机),保存退出后系统无法启动,显示:secure boot failed ,把自己惊出一身冷汗,因为这台笔记本刚好还没开始做备份.....根据错误提示,到bios里面去找相关配置,在Security里面找到了Secure Boot选项,发现果然被设置为Enabled,将其修改为Disabled ,再开机,终于正常启动了。_安装完系统提示secureboot failure

C++如何做字符串分割(5种方法)_c++ 字符串分割-程序员宅基地

文章浏览阅读10w+次,点赞93次,收藏352次。1、用strtok函数进行字符串分割原型: char *strtok(char *str, const char *delim);功能:分解字符串为一组字符串。参数说明:str为要分解的字符串,delim为分隔符字符串。返回值:从str开头开始的一个个被分割的串。当没有被分割的串时则返回NULL。其它:strtok函数线程不安全,可以使用strtok_r替代。示例://借助strtok实现split#include <string.h>#include <stdio.h&_c++ 字符串分割

2013第四届蓝桥杯 C/C++本科A组 真题答案解析_2013年第四届c a组蓝桥杯省赛真题解答-程序员宅基地

文章浏览阅读2.3k次。1 .高斯日记 大数学家高斯有个好习惯:无论如何都要记日记。他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢?高斯出生于:1777年4月30日。在高斯发现的一个重要定理的日记_2013年第四届c a组蓝桥杯省赛真题解答

基于供需算法优化的核极限学习机(KELM)分类算法-程序员宅基地

文章浏览阅读851次,点赞17次,收藏22次。摘要:本文利用供需算法对核极限学习机(KELM)进行优化,并用于分类。

metasploitable2渗透测试_metasploitable2怎么进入-程序员宅基地

文章浏览阅读1.1k次。一、系统弱密码登录1、在kali上执行命令行telnet 192.168.26.1292、Login和password都输入msfadmin3、登录成功,进入系统4、测试如下:二、MySQL弱密码登录:1、在kali上执行mysql –h 192.168.26.129 –u root2、登录成功,进入MySQL系统3、测试效果:三、PostgreSQL弱密码登录1、在Kali上执行psql -h 192.168.26.129 –U post..._metasploitable2怎么进入

Python学习之路:从入门到精通的指南_python人工智能开发从入门到精通pdf-程序员宅基地

文章浏览阅读257次。本文将为初学者提供Python学习的详细指南,从Python的历史、基础语法和数据类型到面向对象编程、模块和库的使用。通过本文,您将能够掌握Python编程的核心概念,为今后的编程学习和实践打下坚实基础。_python人工智能开发从入门到精通pdf