V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
feng32
V2EX  ›  程序员

请教一个 Python 正则表达式问题

  •  
  •   feng32 · 2018-01-25 15:03:05 +08:00 · 2095 次点击
    这是一个创建于 2498 天前的主题,其中的信息可能已经有所发展或是发生改变。
    Python 2.7.6 (default, Nov 23 2017, 15:49:48) 
    [GCC 4.8.4] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    
    >>> re.search("(switchport)?", "  switchport trunk allowed vlan 10").groups()
    (None,)
    >>> re.search("(switchport)", "  switchport trunk allowed vlan 10").groups()
    ('switchport',)
    

    如上,为什么加了问号后,匹配出来的就变成 None 了?难道问号不能作用于一个 group ?

    如果我要用从 m.groups() 中判断是否匹配了特定关键字,需要怎么写?

    18 条回复    2018-01-26 11:55:23 +08:00
    Enochyun
        1
    Enochyun  
       2018-01-25 15:22:59 +08:00
    你匹配的内容里面没有?号 当然是 none 了。
    feng32
        2
    feng32  
    OP
       2018-01-25 15:23:58 +08:00
    @Enochyun 问号不是代表 0 个或 1 个表达式的含义吗?
    wlsnx
        3
    wlsnx  
       2018-01-25 15:24:41 +08:00   ❤️ 1
    In [23]: re.search?
    Signature: re.search(pattern, string, flags=0)
    Docstring:
    Scan through string looking for a match to the pattern, returning
    a match object, or None if no match was found.
    File: ~/.pyenv/versions/3.6.4/lib/python3.6/re.py
    Type: function

    找到一个匹配就返回,很明显 "(switchport)?" 可以匹配 ""
    feng32
        4
    feng32  
    OP
       2018-01-25 15:33:25 +08:00
    @wlsnx 那么如果我要实现匹配 n 个可选关键字,应该就不能把正则写成 (aaa)?( bbb)?( ccc)? 的形式了,这种情况有解决方法吗?
    imn1
        5
    imn1  
       2018-01-25 15:33:51 +08:00
    没看过源码,但从经验来看,py 的 re 基本上是最小匹配优先
    例如 findall 如果出现两个“零或多个”不定长度,匹配结果就往往不是预期结果了
    geelaw
        6
    geelaw  
       2018-01-25 15:34:40 +08:00
    你可以写 aaa|bbb|ccc,如果你一次只想要一个。

    或者采用展开的形式:aaa(bbb)?(ccc)?|bbb(ccc)?|ccc
    wlsnx
        7
    wlsnx  
       2018-01-25 15:36:21 +08:00
    你在这些可选关键字周围加一些必选关键字就行了
    scriptB0y
        8
    scriptB0y  
       2018-01-25 15:39:15 +08:00
    这是一个正则表达式的问题,和 Python 没什么关系。

    你应该看一下贪心 match 和惰性 match 的却别 https://stackoverflow.com/questions/2301285/what-do-lazy-and-greedy-mean-in-the-context-of-regular-expressions

    > 那么如果我要实现匹配 n 个可选关键字

    这个在 python 里面不用匹配,用搜索比较好一些。re.findall(r"(aaa|bbb|cc)", string)
    Aevery
        9
    Aevery  
       2018-01-25 15:40:40 +08:00
    *相当于匹配最少 0 到无限次, +相当于匹配最少 1 次到无限次,而 ?是匹配最少 0 次到最多 1 次。。。lz 可以试试用”+“
    feng32
        10
    feng32  
    OP
       2018-01-25 15:48:57 +08:00
    @scriptB0y 实际上更完整的场景是这样的

    我设计了一个简单的模板语言,支持 blablabla {var1} {var2} bla <flag1> <flag2> blabla 这样的语法

    {var1} 是一个变量,编译成了正则表达式 ([^ ]+)
    <flag1> 是一个可选参数,可以出现 0 次 或 1 次,编译成了正则表达式 (flag1)?

    最后将所有捕捉到的 regex groups 再映射到原变量返回给用户

    这个模板本身是灵活的,用户可以把 <flag1> 放在最前面,甚至也可以一行就一个 <flag1>

    这种情况下感觉启用贪婪匹配模式就可以解决问题了吧?
    p2pCoder
        11
    p2pCoder  
       2018-01-25 15:48:58 +08:00
    ```
    import re
    re.search("(switchport)?", " switchport trunk allowed vlan 10").groups()
    (None,)

    re.findall("(switchport)?", " switchport trunk allowed vlan 10")
    ['',
    '',
    'switchport',
    '',
    '',
    '',
    '',
    '',
    '',
    '',
    '',
    '',
    '',
    '',
    '',
    '',
    '',
    '',
    '',
    '',
    '',
    '',
    '',
    '',
    '',
    '']

    re.search("(switchport)+", " switchport trunk allowed vlan 10").groups()
    ('switchport',)

    re.findall("(switchport)+", " switchport trunk allowed vlan 10")
    ['switchport']
    ```
    feng32
        12
    feng32  
    OP
       2018-01-25 15:53:06 +08:00
    @p2pCoder 我在楼上补充了一下实际的场景,findall 虽然也能捕捉到目标字符,但是干扰项有点太多了
    p2pCoder
        13
    p2pCoder  
       2018-01-25 15:57:49 +08:00
    @feng32 所以为什么不像 9 楼说的 用+
    feng32
        14
    feng32  
    OP
       2018-01-25 15:59:49 +08:00
    @p2pCoder 因为 flag1 可以不存在
    scriptB0y
        15
    scriptB0y  
       2018-01-25 16:09:14 +08:00
    @feng32 你这是一个词法分析了吧,可以看一下内置的库 https://docs.python.org/3.6/library/shlex.html
    feng32
        16
    feng32  
    OP
       2018-01-25 16:20:26 +08:00
    @scriptB0y 实际上就是一个以正则表达式为中间代码的模板解析器,当我用 30 行 Python 把它写出来的时候自己也挺惊讶的,而且发现它也挺好用的,今天刚遇到这个问题

    正规的词法分析、语法分析之前上大学的时候也做过,不过暂时不准备替换重量级的方案; shlex 这个库听过但是没详细了解,后面可以花点时间看看
    windvans
        17
    windvans  
       2018-01-25 21:11:24 +08:00
    ?可以匹配 0 次,这个可能是和 python 的 re 匹配原则有关,如果是贪心的话,应该先匹配有的

    你这个确实用 find 比较好
    zhangsen1992
        18
    zhangsen1992  
       2018-01-26 11:55:23 +08:00
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1026 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 20:45 · PVG 04:45 · LAX 12:45 · JFK 15:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.