【问题标题】:Perl like regex in PythonPerl 像 Python 中的正则表达式
【发布时间】:2011-02-07 22:02:07
【问题描述】:

在 Perl 中,我会做这样的事情来获取正则表达式中的不同字段,用 () 分隔不同的字段并使用 $ 获取它们

foreach $line (@lines)
{
 $line =~ m/(.*?):([^-]*)-(.*)/;
  $field_1 = $1
  $field_2 = $2
  $field_3 = $3
}

我怎么能在 Python 中做这样的事情?

【问题讨论】:

    标签: python regex perl


    【解决方案1】:

    您的 sn-p 的“规范”Python 翻译...:

    import re
    
    myre = re.compile(r'(.*?):([^-]*)-(.*)')
    for line in lines:
        mo = myre.search(line)
        field_1, field_2, field_3 = mo.groups()
    

    导入re 是必须的(导入通常在模块顶部完成,但这不是强制性的)。预编译 RE 是可选的(如果您改用 re.search 函数,它将即时编译您的模式)但建议使用(因此您不依赖已编译的 RE 对象的模块缓存来提高性能,并且为了拥有一个 RE 对象并调用其方法,这在 Python 中更为常见)。

    您可以使用match 方法(无论您的模式是否以'^' 开头,它总是尝试从头开始匹配)或search 方法(尝试在任何地方进行匹配);对于您给定的模式,它们应该是等效的(但我不是 100% 确定)。

    .groups() 方法返回所有匹配的组,因此您可以一次性将它们全部分配(在 Python 中使用列表,就像在 Perl 中使用数组一样,可能更正常,但由于您选择在Perl 你也可以在 Python 中做同样的事情)。

    如果任何行与 RE 不匹配,这将失败并出现异常,如果您知道它们都匹配,这很好(我不确定您的 Perl 的行为是什么,但我认为它会“重用”前一个而是匹配行的值,这很奇怪...除非您再次知道所有行都匹配;-)。如果您只想跳过不匹配的行,请将最后一条语句更改为以下两条:

        if mo:
            field_1, field_2, field_3 = mo.groups()
    

    【讨论】:

      【解决方案2】:

      在 Perl 中,使用数组比在一堆标量后面加上数字要好得多。例如

      foreach my $line ( @lines ) { 
          my @matches = ( $line =~ m/(.*?):([^-]*)-(.*)/ );
          ...
      }
      

      在 Python 中,re 模块返回一个包含捕获组信息的匹配对象。所以你可以写:

      match = re.search( '(.*?):([^-]*)-(.*)', line )
      

      那么您的匹配项将在match.group(1)match.group(2) 等中提供。

      【讨论】:

        【解决方案3】:

        Python 通过 re 模块支持正则表达式。 re.search() 方法返回一个 MatchObject ,它具有像 group() 这样的方法,您可以使用它们来检索“捕获组”信息。

        例如:

        m = re.search(r'(.*?):([^-]*)-(.*)', line)
        field_1 = m.group(1)
        field_2 = m.group(2)
        field_3 = m.group(3)
        

        【讨论】:

          【解决方案4】:

          别忘了在 Python 中,TIMTOWTDI ;)

          import re
          p = re.compile(r'(\d+)\.(\d+)')
          num_parts = p.findall('11.22   333.444') # List of tuples.
          print num_parts                          # [('11', '22'), ('333', '444')]
          

          【讨论】:

          • 我认为您将 Python 与 Perl 混淆了;只需阅读import this(即Python之禅,或只是python -c "import this" |grep -i there
          • @AleksiTorhamo 也许你把严肃和玩笑混为一谈了? ;)
          • 啊,很好 :-) 只是这是我一天内第二次碰到有人这么说,所以我想我最好在幼稚/信息丰富的方面犯错 :) (是的,我很确定那个 other 是认真的 :D)
          【解决方案5】:

          作为一个替代示例,python 为named capture groups 提供了非常好的支持(事实上,python 率先支持命名捕获组)。

          要使用命名的捕获组,您只需在捕获组的左括号内添加?P<the_name_of_the_group>

          这使您可以非常轻松地在字典中获取所有匹配项:

          >>> import re
          >>> x = re.search("name: (?P<name>\w+) age: (?P<age>\d+)", "name: Bob age: 20")
          >>> x.groupdict()
          {'age': '20', 'name': 'Bob'}
          

          这是 OP 的示例,已修改为使用命名捕获组

          import re
          
          find_fields_regex = re.compile(r'(?P<field1>.*?):(?P<field2>[^-]*)-(?P<field3>.*)')
          for line in lines:
              search_result = find_fields_regex.search(line)
              all_the_fields = search_result.groupdict()
          

          现在all_the_fields 是一个字典,其键对应于捕获组名称(“field1”、“field2”和“field3”),值对应于各个捕获组的内容。

          为什么你应该更喜欢命名捕获组

          • 使用命名的捕获组,无论您修改正则表达式模式以添加更多捕获组还是删除现有捕获组,所有内容仍会被放入正确键下的字典中。但是如果没有命名的捕获组,每次组数发生变化时,您都必须仔细检查变量分配。
          • 命名的捕获组使您的捕获组能够自我记录。
          • 如果需要,您仍然可以使用数字来指代组:
          >>> import re
          >>> x = re.search("name: (?P<name>\w+) age: (?P<age>\d+)", "name: Bob age: 20")
          >>> x.groupdict()
          {'age': '20', 'name': 'Bob'}
          >>> x.group(1)
          'Bob'
          >>> x.group(2)
          '20'
          

          一些不错的正则表达式资源:

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-03-14
            • 2012-07-22
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多