代码之家  ›  专栏  ›  技术社区  ›  Andre Miller

如何将具有命名组的perl regex转换为python?

  •  3
  • Andre Miller  · 技术社区  · 17 年前

    我正在尝试转换在 Video::Filename perl模块到python 2.5.4 regex解析文件名

    # Perl > v5.10
    re => '^(?:(?<name>.*?)[\/\s._-]*)?(?<openb>\[)?(?<season>\d{1,2})[x\/](?<episode>\d{1,2})(?:-(?:\k<season>x)?(?<endep>\d{1,2}))?(?(<openb>)\])(?:[\s._-]*(?<epname>[^\/]+?))?$',
    

    我也想使用命名组,我知道在python中,命名组的regex扩展是不同的,但我对语法不是百分之百确定。

    这就是我所尝试的:

    # Python (not working)
    r = re.compile(r'^(?:(?P<name>.*?)[\/\s._-]*)?(?P<openb>\[)?(?P<season>\d{1,2})[x\/](?P<episode>\d{1,2})(?:-(?:\kP<season>x)?(?P<endep>\d{1,2}))?(?(P<openb>)\])(?:[\s._-]*(?P<epname>[^\/]+?))?$')
    

    我得到的错误是:

       raise error, v # invalid expression
    sre_constants.error: bad character in group name
    

    例如,我成功地转换了这个,它工作了。但上面的那个我似乎不太明白。我在python中得到一个编译错误。

    # Perl:
    re => '^(?:(?<name>.*?)[\/\s._-]+)?(?:s|se|season|series)[\s._-]?(?<season>\d{1,2})[x\/\s._-]*(?:e|ep|episode|[\/\s._-]+)[\s._-]?(?<episode>\d{1,2})(?:-?(?:(?:e|ep)[\s._]*)?(?<endep>\d{1,2}))?(?:[\s._]?(?:p|part)[\s._]?(?<part>\d+))?(?<subep>[a-z])?(?:[\/\s._-]*(?<epname>[^\/]+?))?$',
    
    # Python (working):
    r = re.compile(r'^(?:(?P<name>.*?)[\/\s._-]+)?(?:s|se|season|series)[\s._-]?(?P<season>\d{1,2})[x\/\s._-]*(?:e|ep|episode|[\/\s._-]+)[\s._-]?(?P<episode>\d{1,2})(?:-?(?:(?:e|ep)[\s._]*)?(?P<endep>\d{1,2}))?(?:[\s._]?(?:p|part)[\s._]?(?P<part>\d+))?(?P<subep>[a-z])?(?:[\/\s._-]*(?P<epname>[^\/]+?))?$')
    

    我不知道从哪里开始找。

    4 回复  |  直到 17 年前
        1
  •  6
  •   Martijn Pieters    17 年前

    你的翻译有两个问题。首先,第二次提到 openb 它周围有额外的圆括号,使它成为 conditional expression ,不是命名表达式。

    接下来是你没有翻译 \k<season> backreference ,Python使用 (P=season) 以匹配相同的。以下是我的汇编:

    r = re.compile(r'^(?:(?P<name>.*?)[\/\s._-]*)?(?P<openb>\[)?(?P<season>\d{1,2})[x\/](?P<episode>\d{1,2})(?:-(?:(?P=season)x)?(?P<endep>\d{1,2}))?(?(openb)\])(?:[\s._-]*(?P<epname>[^\/]+?))?$')
    

    如果我是你,我会使用re.verbose将这个表达式拆分为多行,并添加大量的文档,以便将来在需要保持可维护性的情况下继续理解表达式。

    (实现第二个后编辑 OpenB 引用是一个条件表达式,并正确地翻译backreference)。

        2
  •  2
  •   jitter    17 年前

    我找到了冒犯的部分,但如果不把我的思想集中在整个事情上,我就无法弄清楚到底是什么地方出了问题。

    r = re.compile(r'^(?:(?P<name>.*?)[\/\s._-]*)?(?P<openb>\[)?(?P<season>\d{1,2})[x\/](?P<episode>\d{1,2})(?:-(?:\kP<season>x)?(?P<endep>\d{1,2}))?
    
    (?(P<openb>)\]) // this part here causes the error message
    
    (?:[\s._-]*(?P<epname>[^\/]+?))?$')
    

    问题似乎在于python中的组名必须是有效的python标识符(检查 documentation )括号似乎是问题所在。移除它们会给

    (?(P<openb>)\]) //with parentheses
    (?P<openb>\])   //without parentheses
    
    redefinition of group name 'openb' as group 6; was group 2
    
        3
  •  0
  •   Lennart Regebro    17 年前

    这些正则表达式是一个病态的、扭曲的思想的产物…-)

    无论如何,(?())是python和perl中的条件,上面的perl语法看起来应该与python语法相同,即,它对名为exists的组的值为true。

    从哪里开始寻找?模块文档如下:

    http://docs.python.org/library/re.html http://www.perl.com/doc/manual/html/pod/perlre.html

        4
  •  0
  •   Bite code    17 年前

    我可能是错的,但你试图用以下方法获得后参考:

    (?:\k<season>x)
    

    不是语法吗 \g<name> 在蟒蛇?