chenfantech 发表于 2021-3-10 14:40:48

关于正则表达式的疑问

最近看了python视频,其中57讲正则表达式,产生了一个疑问

import re

re.search(r'({0,1}\d\d)\.','245.')#这个表达式最后匹配出‘45.’


re.search(r'({0,1}\d\d|2\d)\.','245.')   #而这个表达式匹配出'245.'

姑且称   '({0,1}\d\d)\.'为表达式1,'({0,1}\d\d|2\d)\.'为表达式2 ,那么表达式2是表达式1再 或上一个2\d

我的疑问是,若匹配是从最左边开始, 那字符串'245.' 在表达式1会匹配出‘45.’,但是在表达式2按匹配最左边的原则,应该匹配结果也应该是'45.'才对吧?
为什么是 '245.'   

小白一枚,刚接触正则表达式,用的是idle3.8.1做的实验,求大神们解惑?!   

lei1996 发表于 2021-3-11 00:13:51

https://www.jianshu.com/p/dab17fb8bb3e
这篇文章应该对你有帮助

chenfantech 发表于 2021-3-11 09:17:09

lei1996 发表于 2021-3-11 00:13
https://www.jianshu.com/p/dab17fb8bb3e
这篇文章应该对你有帮助

感谢您的回答,文章我学习了一下,主要点应该是
1. 匹配条件是从左边到右边依次匹配
2. 匹配输出结果是按照 原先待匹配的字符串的字符顺序(从左到右)的第一个匹配结果
3. 第一条件匹配到字符后,后面的条件是在   原来的字符减去已经匹配的字符上进行匹配

上面3点的意思我大概了解,文中的例子也看懂了,但是结合我这个例子,又有矛盾的地方,我再分析一下您看是不是?
原题是:
({0,1}\d\d|2\d)\.    这个表达式 来匹配   字符串 ‘245.’   (字符串后面有一个'.')

如果按上面的文章所说,   那第一个子表达式{0,1}\d\d匹配到 '45'
那剩下的字符串是'2.'
这样第二个子表达式 2\d   就应该找不到匹配?   
那最后的结果应该是第一个表达式找到的‘45’并且加上最后的'.'

那结果还是输出'45.'不是吗?望解惑,感谢感谢

lei1996 发表于 2021-3-11 11:52:37

文章的意思应该不是说 “匹配条件从左边到右边依次匹配” 的吧
文章的栗子 "aaabbbccc".match(/cc|bb|aa/g); //Array [ "aa", "bb", "cc" ] 表示的不是匹配是按"aaabbbccc"的顺序来的吗并不是按cc|bb|aa中cc在前面来先匹配的的

所以当要匹配的字符串是‘245.’,它会优先找到能匹配到245的表达式2\d

chenfantech 发表于 2021-3-11 14:42:51

lei1996 发表于 2021-3-11 11:52
文章的意思应该不是说 “匹配条件从左边到右边依次匹配” 的吧
文章的栗子 "aaabbbccc".match(/cc|bb|aa/g ...

再次感谢您的回复

结合上面我说的3个点,我先来说说我对"aaabbbccc".match(/cc|bb|aa/g); //Array [ "aa", "bb", "cc" ] 这条的匹配的分析,您看看我说的对不对,我这里分4步
step 1:
首先对于原字符串'aaabbbccc'    ‘cc’先匹配好了原字符串中的'cc',然后由于第一个条件cc已完成匹配,所以
剩下的字符串其实是'aaabbbc'   (这里的依据用到了上面说的3点的 第1 和 第3点)

step 2:
然后表达式bb 匹配 剩下的字符串'aaabbbc',那么匹配到这个字符串中的‘bb’后,剩下的字符串应该是'aaabc',这里还是用到了上面的第1,3两点

step 3:
最后表达式aa匹配字符串'aaabc',那么这样匹配到字符串中的'aa'后,最后字符串剩下'abc',到这一步匹配完毕

step 4:
最后一步就是输出了,经过前面三步,输出应该为 'cc' , ‘bb’和 'aa', 但是根据上面的第2点,要根据"原待匹配的字符串" 来进行输出,原字符串为 'aaabbbccc', 那么输出顺序自然还是 'aa''bb''cc'

所以结果输出结果是aabbcc

下面是引用原网页里的原文说明(原文第三段):
查找的循序是按照匹配条件左边开始到右边匹配,但是返回的结果是按照待匹配的字符串的字符顺序(从左到右)的第一个匹配结果进行输出。并且第一条件被匹配到字符串之后,后面的条件是在原来字符串减去已经匹配到的字符之后再进行查找匹配

分别对应我说的 第1点, 第3点   和 第2点

原文中的"aaabbbccc".match(/a|ab/g); //Array [ "a", "a", "a" ] 以及
"aaabbbccc".match(/ab|a/g); //Array [ "a", "a", "ab" ] 这两个例子 也可以安装我上面说的分析

以上说的是否有错,一起讨论下,再次感谢


lei1996 发表于 2021-3-11 16:22:45

不好意思没有通读那篇文章理解错误了
不过我认为他的解读也有问题对于"aaabbbccc".match(/cc|bb|aa/g); //Array [ "aa", "bb", "cc" ] 我的理解是
1.从"aaabbbccc" 的首位a开始先匹配cc不符合然后匹配 bb 不符合然后匹配 aa符合
2."aaabbbccc"变为"abbbccc"再按照cc|bb|aa从左到右依次判断匹不匹配,而不是先按cc|bb|aa中的顺序先用cc把字符串匹配完剩下"aaabbbc"的再给bb和aa
按这样理解他的栗子也都能解释你的问题也能解释

chenfantech 发表于 2021-3-11 17:10:56

lei1996 发表于 2021-3-11 16:22
不好意思没有通读那篇文章理解错误了
不过我认为他的解读也有问题对于"aaabbbccc".match(/cc|bb|aa/g) ...

您好

针对您的理解,我有一点不解的地方,您说了2点,我分别说一下
您说“1.从"aaabbbccc" 的首位a开始先匹配cc不符合然后匹配 bb 不符合然后匹配 aa符合”
—— 这里说到“从首位a开始,先匹配cc不符合”, 那这么说若例子改为"aaabbbccc".match(/cc/g),即只匹配cc的话,那肯定能匹配到原字符串中的cc,所以是不是每一个表达式进行全字符串的比较?

“2.aaabbbccc"变为"abbbccc”
——假设1点成立,若字符串变为“abbbccc”,再用cc|bb|aa从左到右依次匹配,那这样首字母是a,第2字母是b,那按您上面第一点说的,cc不匹配,bb也不能匹配,aa也无法匹配,那到第二个字符串,就结束匹配了,那最后的结论就只有 aa

所以我认为您第1点说的,“先匹配cc不符合”是不是有待商榷?cc是否要先匹配完所有的字符串?


========================
还有附加一点,我上面帖子的分析还有一点我也不是很理解,按照我上面说的字符串最后剩下的会是'abc',我做过实验"aaabbbccc".match(/cc|bb|aa|abc/g);再增加一个abc的表达式,是找不到的,那这可能是其他问题,这里不讨论,主要还是针对这个表达式的理解和我的问题

万分谢谢,盼回复

lei1996 发表于 2021-3-11 17:23:02

我的意思是如果都匹配不到的话字符串的位置就后移   当“abbbccc”都不匹配时就变成“bbbccc”意思大概是这样 但怎样实现的就不太了解了

lei1996 发表于 2021-3-11 17:29:33

你的   实验"aaabbbccc".match(/cc|bb|aa|abc/g);再增加一个abc的表达式,是找不到的    不就表示实际情况可能并不是按照文章那样匹配的吗

Hela 发表于 2021-3-11 18:29:41

马克一下学习

chenfantech 发表于 2021-3-11 21:36:15

lei1996 发表于 2021-3-11 17:29
你的   实验"aaabbbccc".match(/cc|bb|aa|abc/g);再增加一个abc的表达式,是找不到的    不就表示实际情 ...

我也做了   "aaabbbccc".match(/cc|bb|aa|ab/g)和"aaabbbccc".match(/cc|bb|aa|bc/g);

结果 aa ab bb cc和 aa bb bc cc   

那根据最后 剩下的abc 貌似也是符合要求   

其实我们参见整个字符串,确实也不存在abc 这样的组合,所以感觉还是哪里没有想通。。。

chenfantech 发表于 2021-3-12 23:07:16

lei1996 发表于 2021-3-11 16:22
不好意思没有通读那篇文章理解错误了
不过我认为他的解读也有问题对于"aaabbbccc".match(/cc|bb|aa/g) ...

您好,您这个解释我思考了一下,是正确的的,那篇文章的理解确实有问题
总结了一下应该是这样的

1、根据表达式,从左到右,最优先的字符会被匹配出来,根据cc|bb|aa的例子,三个表达式都能匹配出字符,但是根据原字符串aaabbbccc,aa是最先被匹配出来的,所以第一次匹配确实是aa被匹配出,而不是我说的用cc逐一匹配(这里说明一下,虽然表达式cc再左边,但是原字符串匹配的位置内容'cc'却是在内容'aa'的后面,所以其实是通过了表达式aa 已经匹配成功,有点绕,要认真揣摩)

2、匹配后的字符串,是原字符串减去已匹配成功的字符串,即abbbccc,然后重新通过cc|bb|aa的表达式重新匹配,这时候匹配出bb,原因同上(因为bb在最左边)

3、通过第三次匹配出cc后,匹配已成功,是aa bb cc,此时字符串确实剩下abc,我这里理解,字符串不是连续的,并且如果加入表达式变为 cc|bb|aa|abc本身也是不能找到abc这个字符串,若原字符串本身正常含有abc字符串会自然被匹配出来,但是现在这个abc是“零碎的”,所以,加上这个abc条件,也是无法匹配(这里是我自己的一个理解,姑且先这么理解用来解决为什么最后剩abc无法匹配的问题)

4、还有一点,表达式的先后顺序再上面这个例子看起来不重要,其实是非常重要的影响很大的,那个链接里表达式ab|a和a|ab这个例子非常明显的说明这一点,我们看匹配要结合表达式顺序和原字符串匹配顺序这两点来看,不能分割开来看

5、最后回归我的问题,表达式1虽然能完成匹配但结果是45.而表达式2匹配出了245. 那么按照原字符串匹配顺序,其实这个表达式是被表达式2给匹配出来,也符合上面的分析逻辑(其实这个问题是源于视频里的用正则匹配IP地址,最后一段为什么超过199只会匹配出前两位,比如205只会匹配出20,但是第一段ip却是可以超过199,都正常,这些都可以按上面的逻辑分析出来,但是我个人感觉比较绕)

6、推荐一个网站和一个工具,有助于理解正则表达式
https://regexper.com       —— 这个网站很好的把抽象的表达式变成图形,我们更好理解
Match Tracer         —— 这个工具可以一步一步让我们看看是按什么顺序来匹配出字符串的

最后谢谢 lei1996的耐心解答

chenfantech 发表于 2021-3-12 23:10:50

lei1996 发表于 2021-3-11 16:22
不好意思没有通读那篇文章理解错误了
不过我认为他的解读也有问题对于"aaabbbccc".match(/cc|bb|aa/g) ...

确实是按这么理解~~

感谢解答
页: [1]
查看完整版本: 关于正则表达式的疑问