highwind
(highwind)
1
s = “hello123world456www7.89你好001”
match = re.findall(r'\d+(\D+)', s)
['world', 'www', '.', '你好']
match = re.findall(r'\d+(\D+)\d+', s)
['world', '.']
match = re.findall(r'\d+(\D+)\d', s)
['world', 'www', '你好']
请问各位大大为啥 \d+在字符串末尾的时候会产生不同的匹配呀,难道是这个d代表除了0~9之外其他字符吗?谢谢解答哟
Niceb
(Niceb)
2
好神奇, 给人的感觉是从前往后匹配的时候, 如果前面匹配到了 那匹配到的字符就不参加后面的匹配了
比如说Match2中, 第一个匹配到的world 完整的匹配应该是“123world456”, 匹配后面的字符串的时候"123world456"被排除了(也就是后续匹配的时候只有“www7.89你好001”参加了匹配),所以没有匹配到“www”这个结果
我说的这个“被排除了”, 可能更合适的表达应该是 下次匹配从“123world456”之后开始进行,所以就没有包括“456”这三个数字,,不知道表达清楚了没有。。。
后面的也是类似的。。
之前用py好像没有关注到类似的情况…
先确定这几个概念:
- \d+ 表示匹配数字
- \D+ 表示匹配到非数字字符
- re.findall 表示返回 s 里所有匹配到括号里的项,也就是非数字的内容
好了,我们来解题:
-
Match1: 必须返回前面有数字,后面是字符的内容。这样第一个 hello 前面没数字,后续 world, www, 你好都有数字在前面,最后一个数字 001 后没有字符,所以返回正确
-
Match2: 必须返回前面有数字,中间是字符,后面还跟着数字的内容。这样第一个 hello 前面没数字但后面有,不正确,world 前面有123,后面又456,所以匹配到,然后 www 因为前面的 456 已经被 world 部分匹配到了,所以算前面没数字,略过,7.89 正好符合前后有数字,中间的点不是数字的情况,匹配到了,再后面的“你好”因为前面的89被点匹配过,即使后面有数字也不满足前面有数字的情况,所以只能抱歉,最终结果是 ‘world’, ‘.’,结果也正确
-
Match3: 前后必须有数字,但最后一个数字因为没有数量标记,所以必须只有1个。我们再来看看:hello 前面没数字,略过,world 前面有 123,后面 456 里找到了4 (只匹配一个),剩下56用于后续匹配,于是很开森的, www 前面有 56,后面有 7,匹配到了,再往后看 .89 前面没数字,略过,因为没匹配到所以顺延到“你好”字符上,这个字符前面有89,后面有0,很好又匹配到了,最后的01匹配不到,所以最后结果是 ‘world’, ‘www’, '你好‘,结果还是正确
正则表达式写之前脑子里一定要先过一遍,匹配过的不会介入下一次匹配,你用的是 findall,你要用 match 或 search 则只匹配一次,行为又不一样了。
你的疑问是 \d+ 在字符串末尾产生了不同的结果,以为它有多个匹配行为,但实际上从头到尾 \d 都表示匹配数字, + 则表示最少匹配一次或多次,原则一直没变,变的是匹配一次后余下的字符是动态的,你的脑子里没一轮轮的去过滤匹配字符串,一直都拿原始字符串去过滤,所以看到结果摸不到头脑
3 个赞
python 正则匹配即丢弃。可以用断言
match = re.findall(r'(?<=\d)(\D+)(?=\d)', s)
另外 re 的断言限宽。因此如果是其他案例(例如\d+abcd这类)需要安装 regex 模块
2 个赞
r'\d+(?:\D+)'
['123world', '456www', '7.', '89你好']
r'\d+(?:\D+)\d+'
['123world456', '7.89']
r'\d+(?:\D+)\d'
['123world4', '56www7', '89你好0']
用非捕获组,就能清晰的看到为什么了