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 · 2473 次点击
    这是一个创建于 2944 天前的主题,其中的信息可能已经有所发展或是发生改变。
    >>> 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 写的 更详细。
    jin6220
        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   ·   实用小工具   ·   5538 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 36ms · UTC 08:53 · PVG 16:53 · LAX 00:53 · JFK 03:53
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.