其他教程

其他教程

Products

当前位置:首页 > 其他教程 >

如何用正则表达式提取所有符合「介于两个特定字符串a和b之间」这一条件的内容?

GG网络技术分享 2025-03-18 16:14 6


问题描述:

例如有这样一段文本(无标点符号):

请问您的姓名是什么姓名张三对吗

现在需要提取姓名,即\"张三\"。需要提取的姓名,位于\"姓名\"和\"对\"这两个固定的字符串之间,故使用以下正则表达式规则:

(?<=姓名)(.*?)(?=对)

提取结果只有一条,如下:

是什么姓名张三

请问怎样的正则表达式可以完整地返回以下两个结果:

是什么姓名张三

张三

网友观点:

完整地返回以下两个结果:
(?<=姓名)(.*?((?<=姓名).*?)?)(?=对)/)
第一个子匹配结果:是什么姓名张三
第二个子匹配结果:张三

如果要直接获取“张三”
(?<=姓名)((?:(?!姓名).)*?)(?=对)

不用这么复杂把!你这里主要是想搞清楚一个贪婪和非贪婪匹配的区别。
我理解贪婪程序是从姓名开始找,找到第一个对结束。然后再往后找第二个对。所以我认为 (?<=姓名)(.*?)(?=对) 非贪婪匹配就是是什么姓名张三
第一个匹配我就不说了。我觉得第二个匹配这么写你可能好理解一些。
re.search(r\'(?<=姓名).*(?<=姓名)(.*)(?=对)\',youstr)
re.search(r\'(?<=姓名)(.{2,4})(?=对)\'youstr)

正则表达式使用

一、从"hello"开始,我们想查找出某个字符串是否"hello“?

方案1:使用正则表达式 hello 即可。对,没有看错,这就是正则表达式。

其实正则说白了就是匹配我们需要的东西,类似Windows资源管理器,我们需要搜某个文件或者文件夹,直接输入文件名即可。只不过后面我们的需求不止如此,举个栗子,我现在要找出所有.txt的文件出来,我们会在搜索框输入*.txt,*就是一个占位符。再来个栗子,我们要匹配123三个数字,直接正则表达式123即可,但是如果我们匹配的是邮编,都是数字,此时就得用上正则的特殊语句了。

比如:从上面表达式,"helloabc","abchello","abchellodef"照样会匹配上,但我只需要它找出hello,这明显有缺陷,需要健全下

这时候就得使用元字符了,

元字符,说白了就是资源管理器搜索时的占位符,常用的有
. 匹配除换行符意外的任意字符
\\w 匹配字符数字或者下划线或者汉字
\\s 匹配任意空白符
\\d 匹配数字
\\b 匹配单词的开始或者结束
^ 匹配字符串的开始
$ 匹配字符串的结束

方案2:修改表达式为 \\bhello\\b,其中\\b的意思代表单词的开始或者结尾处,

这样就能过滤掉这些"helloabc","abchello","abchellodef" 非“hello”的单词了,当我们判断“hello ”、“hello world”这种,正则匹配就为true,而匹配"helloabc"这种,就为false。

二、如果,需要匹配的不是"hello" 而是"hello world",这时候该怎么办?

尝试一下:\\bhello\\sworld\\b

这样的会产生个新问题,万一我跟的不只一个空格,而是有多个(我也没法预测几个)。

这里就有另外两个知识点。重复和转义

重复

重复好理解,其实就是这种,不知道出现多少次,或者每个字符匹配规则都一样,我没必要一直写相同的匹配规则。比如上面提到的邮编匹配,6位数字理论都是正确的,那么该怎么写 \\d\\d\\d\\d\\d\\d ,这太麻烦了,来个缩写多好。\\d{8} 代表匹配8位的数字。类似的问题还有很多,比如我也不知道有几位数字,那我就可以写重复一次或者很多次 \\d+等等,其实就是在匹配项后面跟一个缩写符号代表我要的要求而已。
*重复零次或者更多次
+重复一次或更多次
重复零次或者一次
{n}重复n次
{n,}重复n次或更多次
{n,m} 重复n到m次

转义

转义更好理解,如果我们匹配的是一些正则匹配用到的字符,或者特殊符号如退格换行等,避免歧义,我们用\\来转义一下,就ok了,和程序的转义意思一样。
\\*匹配 *
\\b匹配退格符
\\t制表符
\\r换行符
\\(匹配左括号
\\)匹配右括号

方案3:此时我们需要这么写 \\bhello\\b\\s+\\bworld\\b

拆解分析,\\bhello\\b 代表的意思如上所述,匹配单词hello,\\s 代表匹配任意空白符,+ 代表重复前面一个元字符一次或者更多次,所以,\\s+连起来的意思就是匹配任意一个或者多个空白符,\\bworld\\b 规则相同

三、匹配hello world 或者Hello world,即首字符不区分大小写

字符类:
有时候我们拿不准这个地方需要确定哪一个字符,但是我知道哪些字符满足条件,于是把他们都放一起,用"[]" 括起来,表示一个字符类,只要该位置的字符在里面,则算匹配成功
[qwer] 匹配qwer中的任何一个
有时候,如果匹配的是所有的大写字母,那得[ABCDEFGHIJKLMNOPQRSTUVWXYZ] ?麻烦,肯定有缩写形式的
[A-Z]匹配所有大写字母
[0-9]匹配0到9的数字
[A-Za-z]匹配所有英文字母

方案4: \\b[hH]ello\\b\\s*\\bworld\\b 其中[hH]代表,匹配hH中任何一个字符即可

改进:这时候我们匹配,"hello" "helloworld" "hello world" "hello world2"都算匹配上的,而且,hello和world 的首字母不区分大小写:\\b[hH]ello\\b\\s*\\b[wW]orld2?\\b

这样表达式是不是复杂很多了呢

四、变换下需求,hello world 的匹配,中间我不要空格,但是具体是什么无所谓,只要不是空格都可以

反义

有时候,需要查找不属于某个特定规则的字符,而是除了这个规则之外的都可以。比如想查找除了数字以外,其它任意字符都行的情况。这时候就得反义了
如:
\\W 匹配任意不是字母,数字,下划线,汉字的字符
\\S 匹配任意不是空白符的字符
\\D 匹配任意非数字的字符
\\B 匹配不是单词开头或结束的位置
[^x] 匹配除了x以外的任意字符
[^helo] 匹配除了helo这几个字母以外的任意字符

方案5:hello\\S+world

五、此时再增加一类,"hello" "helloworld" "hello world" "hello world2" 其中hello可以用括号括起来,如"(hello)" "(hello)world" "(hello) world" "(hello) world2" 分支条件

我们尝试写一下吧,首先分析, ( 出现0次或者1次,h和H都可以,后面依次ello 然后) 出现0次或者1次,然后空格0次或者多次,然后wW都可以,然后orld,然后2出现0次或者1次

那么写吧:\\(?[hH]ello\\)?\\s*[wW]orld2?

注:这时候都是序列匹配不是单词匹配了,所以加不加\\b\\b判断单词开始结束位置无所谓,可以不加。

但是好像有点bug,你会发现 "(helloworld" "hello)world" 类似这种也会算匹配上的,这就很烦了。我们需要的是()成对出现或者都不出现。

那么此时得考虑分支条件符号了。

分支条件,就是if else 的意思。我们用| 隔开多个匹配项,每个隔开部分当成一个条件匹配想,匹配不上就走下一个匹配条件,一直到所有的分支条件都匹配不上,则算整个正则表达式匹配不上,false.有点像逻辑表达式“或”的感觉,也有短路原则,即,前面匹配上了,不会判断接下来的其他条件。所以得注意条件顺序。

如上面问题,可以这么写:

方案5:\\([hH]ello\\)\\s*[wW]orld2?|[hH]ello\\s*[wW]orld2?

六、此时,改变下需求,我现在需要匹配的是hellohellohello world

分析:对,此时需要重复的是,hello,不是某一个字符了,hello{3}\\s*world 只会是把字符o重复三次

分组:

简单的一比,一句话,我们需要对一块匹配项统一操作,比如重复,到后面高级操作的取值、断言等等,于是用个括号括起来就ok了,我们把括起来的这一部分叫一个分组。

方案6:(hello){3}\\s*world

甚至可以自己按照上面的扩展,比如

首字母不区分大小写:([hH]ello){3}\\s*[wW]orld

重复次数不限制,0次或者多次:([hH]ello)*\\s*[wW]orld

等等


hello world 匹配差不多了,接下来来个难点的,我要匹配ip地址是否合法,怎么搞?

分析:我们发现可以这么写,反正就是三个数后面都带个“.”,最后再跟一个数

方案6:(\\d{1,3}\\.){3}\\d{1,3}

拆解分析:(exp){3}\\d{1,3} 其中exp 为 \\d{1,3}\\. 代表匹配1到3个数字,后面跟一个"." ,(exp){3}就代表,"匹配1到3个数字,后面跟一个."的这个匹配项重复1到3次,即172.18.21.,后面就简单了,\\d{1,3}代表匹配1到3个数字。所以连起来就会匹配到 172.18.21.123

但是,这样还是有问题, 发现我们并没有对数字加任何限制,ip是有规范的,x.x.x.x 四组数,x范围是0到255,所以还是得改进

方案7:((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)

拆解分析:(exp1){3}(exp2) ,其实大结构还是三个数后面带个“.”,最后再跟一个数。关键是(2[0-4]\\d|25[0-5]|[01]?\\d\\d?) 这个分组,首先匹配2,第二位0到4的数字都可以,第三位\\d,连起来就是200-249的数字都能匹配到,然后是| 分支条件,第一位2,第二位5,第三位0到5的数字都可以,即250-255,最后一个分支条件是[01]? 0 或1 出现0次或者1次,\\d 匹配数字,最后一个\\d?匹配数字0次或者一次都可以,连起来就是0到199的数字都可以。以下,三个分支条件共同构成了0-255的IP地址正则匹配。其余都不合法。

其实到这里,正则的基础操作都就差不多了,回顾一下:

一、元字符

二、重复,转义

三、字符类

四、反义

五、分支条件

六、分组

到现在为止,已经能解决基本日常操作。但是还有几个问题解决不了

1)如果我想匹配有重复单词的呢,如 hello hello 或者 nihao nihao 这种都算匹配成功。改怎么做。很明显,我们先得取得前面的一个,后来给后面判断使用。

2)我们想匹配一个字母a,但是,这个字母a后面不能跟着字母b,该怎么做?

3)比如,ababab,我的正则表达式是ab,此时你会发现,它的匹配项是ababab,它匹配最长段落了,其实我要的可能是最短ab,这时该怎么做?

后面就是一些进阶操作了

七、后项引用

八、断言

九、贪婪与懒惰

十、注释

待更……

标签:

提交需求或反馈

Demand feedback