正则 re.findall(r'x?','xy123'),x 重复 0 次是什么意思? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
jin6220
V2EX    Python

正则 re.findall(r'x?','xy123'),x 重复 0 次是什么意思?

  •  
  •   jin6220 2016-11-06 18:35:16 +08:00 2797 次点击
    这是一个创建于 3294 天前的主题,其中的信息可能已经有所发展或是发生改变。
    >>> re.findall(r'xy','xy123') #从源文本 xy123 中找 xy 刚好找到一个。
    ['xy']
    >>> re.findall(r'x','xy123') #从源文本 xy123 中找 x 刚好找到一个。
    ['x']
    >>> re.findall(r'x?','xy123')
    ['x', '', '', '', '', '']

    最后这个实在无法理解,
    从中找 x 重复 0 次或者 1 次,如果 x 重复 1 次,得到 x,
    关键是重复 0 次怎么理解?输出的结果里有 5 个表示空东西的东西,但是源文本 xy123 中没有它啊?!
    16 条回复    2017-07-02 13:57:28 +08:00
    noli
        1
    noli  
       2016-11-06 18:42:58 +08:00 via iPhone
    不要理解为"重复",理解为"匹配"。
    匹配零次,就是匹配一个空集合,显然,任何"东西"都不属于一个空集合。所以 x?,就是匹配字母 x 一次,显然这是跟单独一个 x 是一样的效果,这是因为问号后面没别的条件了
    noli
        2
    noli  
       2016-11-06 18:47:26 +08:00 via iPhone   1
    @noli 然后再看匹配零次,因为只有空元素才能属于空集合。所以,后面字符串有多少个字符,就匹配了多少次空集合
    jin6220
        3
    jin6220  
    OP
       2016-11-06 19:06:13 +08:00
    @noli 好吧 不过 0 次这个实在是头疼
    正则的作用,我粗略理解是从源文字中寻找符合匹配模式的东西,
    x? ,如果?是零次的话,匹配模式是个空集合,但是源文字中不是没有空集合么?
    noli
        4
    noli  
       2016-11-06 19:19:40 +08:00   1
    @jin6220 任何集合与空集的交集,结果都是空集。
    DiamondbacK
        5
    DiamondbacK  
       2016-11-06 19:21:13 +08:00
    'xy123' 长度为 5 ,所以 re.findall 最多可以在 5 个位置尝试匹配。
    第一个位置是在字符串首,匹配到了 'x'。
    然后跳过匹配到的字符串,移到 'y' 前面,进行第二次匹配尝试,匹配到 ''。
    然后往前移动一个字符,即 'y' 和 '1' 中间,进行第三次匹配尝试,匹配到 ''。
    然后往前移动一个字符,即 '1' 和 '2' 中间,进行第四次匹配尝试,匹配到 ''。
    然后往前移动一个字符,即 '2' 和 '3' 中间,进行第五次匹配尝试,匹配到 ''。
    然后往前移动一个字符,即串尾,结束所有匹配尝试。

    任何文本都包含 ''。
    DiamondbacK
        6
    DiamondbacK  
       2016-11-06 19:24:14 +08:00   1
    更正

    'xy123' 长度为 5 ,所以 re.findall 最多可以在 5 个位置尝试匹配。
    第一个位置是在字符串首,匹配到了 'x'。
    然后跳过匹配到的字符串,移到 'y' 前面,进行第二次匹配尝试,匹配到 ''。
    然后往前移动一个字符,即 'y' 和 '1' 中间,进行第三次匹配尝试,匹配到 ''。
    然后往前移动一个字符,即 '1' 和 '2' 中间,进行第四次匹配尝试,匹配到 ''。
    然后往前移动一个字符,即 '2' 和 '3' 中间,进行第五次匹配尝试,匹配到 ''。
    然后往前移动一个字符,即串尾,进行第五次匹配尝试,匹配到 ''。

    任何文本都包含 ''。
    DiamondbacK
        7
    DiamondbacK  
       2016-11-06 19:25:44 +08:00   1
    更正

    'xy123' 长度为 5 ,所以 re.findall 最多可以在 6 个位置 (想像光标插入位置) 尝试匹配。
    第一个位置是在字符串首,匹配到了 'x'。
    然后跳过匹配到的字符串,移到 'y' 前面,进行第二次匹配尝试,匹配到 ''。
    然后往前移动一个字符,即 'y' 和 '1' 中间,进行第三次匹配尝试,匹配到 ''。
    然后往前移动一个字符,即 '1' 和 '2' 中间,进行第四次匹配尝试,匹配到 ''。
    然后往前移动一个字符,即 '2' 和 '3' 中间,进行第五次匹配尝试,匹配到 ''。
    然后往前移动一个字符,即串尾,进行第六次匹配尝试,匹配到 ''。

    任何文本都包含 ''。
    jin6220
        8
    jin6220  
    OP
       2016-11-06 19:33:24 +08:00
    @noli 你看看 @DiamondbacK 写的 更详细。
    in6220
        9
    jin6220  
    OP
       2016-11-06 19:46:11 +08:00
    @DiamondbacK 刚才刚好去搜索了 互联网找到这份内容:
    ’ 对于字符串” 123 “而言,包括三个字符四个位置。正则表达式匹配过程中,如果子表达式匹配到东西,而并非是一个位置,并最终保存到匹配的结果当中。这样的就称为占有字符,而只匹配一个位置,或者是匹配的内容并不保存到匹配结果中,这种就称作零宽度,后续会讲到的零宽度断言等。占有字符是互斥的,零宽度是非互斥的。也就是一个字符,同一时间只能由一个子表达式匹配,而一个位置,却可以同时由多个零宽度的子表达式匹配。‘

    然后看到您的回复,感觉好像是这样子:
    源文件是由两个部分组成,可以看到的占有字符,另一部分是字符两边的位置。
    xy123 是 5 个字符, 6 个位置。
    不过这样的话 6 个位置都符合 x?中 0 次的空集合啊,那这样结果是少匹配到一次 ''???
    这种东西深入理解还要从原理上理解。
    或者从例子中实践记住结果,当个实践派。
    DiamondbacK
        10
    DiamondbacK  
       2016-11-06 19:50:08 +08:00   1
    @jin6220
    /x?/ 是贪婪匹配,匹配尽可能长的字符串,能匹配 'x' 就不匹配 ''。
    jin6220
        11
    jin6220  
    OP
       2016-11-06 20:31:34 +08:00
    源字符: xyx
    或者写成 。 x 。 y 。 x 。(用。表示位置)
    表达式: x?
    Match 1
    Full match 0-1 `x`
    Match 2
    Full match 1-1 ``
    Match 3
    Full match 2-3 `x`
    Match 4
    Full match 3-3 ``
    =。=。=。=。=。=
    >>> re.findall(r'x?','xyx') #正则匹配模式含有空集合
    ['x', '', 'x', '']
    >>> re.findall(r'x??','xyx')
    ['', '', '', '']
    通过实践可知,如果正则匹配模式含有空集合的话,匹配的时候,字符与位置是同时参与的,之前理解的是根据先后关系先字符前面的位置然后是字符。两者同时参与正则模式匹配,根据贪婪模式或者非贪婪模式选其一(匹配字符或者位置)。

    @DiamondbacK
    thekoc
        12
    thekoc  
       2016-11-07 09:35:54 +08:00 via iPhone
    你需要看《精通正则表达式》。

    如果没有一个系统的学习,这些类似困惑会在每次使用正则表达式的时候都阴魂不散…
    samtoto
        13
    samtoto  
       2016-11-07 11:27:55 +08:00
    In [2]: re.findall('x{1}', 'xy123')
    Out[2]: ['x']

    In [3]: re.findall('x{0,1}', 'xy123')
    Out[3]: ['x', '', '', '', '', '']
    irenicus
        14
    irenicus  
       2016-11-07 18:52:11 +08:00 via Android
    你需要看精通正则表达式+1
    贪婪模式下引擎是个吃货,一口吃饱,然后吐出来
    第一步,从
    [xy123] []
    开始,一口口吐出来,直到
    [x] [y123]
    符合了 x ?

    第二步从
    [y123] []开始
    直到
    [][y123]
    也符合 x ?,因为有 0 个 x

    这次引擎一个字符都没吞,如果不吞一个的话,就死循环了,所以必须吞掉一个字符, y 没了

    第三步,从
    [123] []开始,后面和第二步一样

    直到第五步结束后,强行吞掉 3 ,字符串已经没有了
    所以引擎停止,总共执行了 5 次,五次都匹配到了
    irenicus
        15
    irenicus  
       2016-11-07 18:54:09 +08:00 via Android
    至于你这个为啥是六次,我就不知道了,可能是 3 后面还有个\n
    mingyun
        16
    mingyun  
       2017-07-02 13:57:28 +08:00
    @DiamondbacK 学习了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     4907 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 09:41 PVG 17:41 LAX 01:41 JFK 04:41
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86