正则表达式返回第一个和最后一个匹配项,而不是在匹配括号之间返回第一个和第二个匹配项

2024-06-28 15:28:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试解析文本以提取所需的字符串。我在regex中遗漏了一些东西,有人能帮我找出这里的问题吗

这是我的剧本:

import re
a = """
    block1
          #(/*AUTOINSTPARAM*/
        // Parameters
        .THREE          (3),     // comment
        .TWO            (2), // comment
        .ONE    (1))             // comment
        inst1
           (/*AUTOINST*/
        // extra
        // output

    block2
          #(/*AUTOINSTPARAM*/
        // Parameters
        .THREE          (3),     // comment
        .TWO            (2), // comment
        .ONE    (1))             // comment
        inst2
           (/*AUTOINST*/
        // extra
        // output
"""

op = re.findall(r'(\w+)\s*(#\(.*\))?.*?(\w+)\s*\(', a, re.MULTILINE|re.DOTALL)
for i in op:
    print(i[0],i[2])

这是输出:

('block1', 'inst2')

预期产出:

('block1', 'inst1')
('block2', 'inst2')

更新: 正在尝试测试与已接受答案相同的正则表达式的以下输入:

import re
a = """
    except_check
          #(
            .a        (m),
            .b        (w),
            .c        (x),
            .d        (1),
            .e        (1)
        )
        data_check
           (// Outputs

  abc
  #(
    .a                          (b::c)
   )
   mask
   (/*AUTOINST*/

"""

op = re.findall(r'^\s*(\w+)\s*$\n(?:^\s*[#/.].*$\n)*^\s*(\w+)\s*\(', a, re.MULTILINE)
for i in op:
    print(i)

它没有返回任何东西。它应该返回以下内容:

('except_check', 'data_check')
('abc', 'mask')

Tags: importrecheckcommentextraonethreeparameters
3条回答

如果第二组的单词字符位于2个右括号之后,则可以省略re.DOTALL,并使用一个模式,例如使用[\s\S]*?匹配在多行上延伸,直到遇到2个连续括号为止

此模式基于示例数据,并且可能容易出错,因为它依赖于2个括号作为块2之前的最后一部分

^\s*(\w+)\r?\n\s*#\([\s\S]*?\)\s*\).*\r?\n\s*(\w+)

Regex demo

另一个选项是匹配第一个块后不以单词字符开头的行,并在组2中捕获以单词字符开头的行的单词字符

^\s*(\w+)\r?\n[^\S\r\n]*#\(.*(?:\r?\n(?![^\S\r\n]*\w).*)*\r?\n[^\S\r\n]+(\w+)

Regex demo

问题是.*匹配尽可能多的(贪婪)和re.DOTALL。它将尽可能少地匹配整个字符串leavig,以便仍然匹配

(\w+)\s*(#\(.*\))?.*?(\w+)\s*\(
            ^^ this one

基本上,任何带有.*的正则表达式(如果允许.真正捕获所有内容)将只匹配一次或根本不匹配,因为它能够匹配rexpression的其余部分也可以匹配的任何内容

仅仅使用.*?也无法解决这个问题,因为:

字符串的另一个问题是括号。Regex(没有一些奇特的扩展)只能匹配具有有限嵌套的括号。假设AUTOINSTPARAM块中的最大嵌套深度为2,则以下正则表达式将起作用:

vvvvv blockX                                    vvvvv instX
(\w+)\s*(#\([^(]*(\([^)]*\)[^()]*)*\))?[^\n]*\s*(\w+)\s*\(
                  ^^inner^^
          ^^ outer bracket         ^^  

这些[^()]组有一个.的装置,通过忽略它们来防止它吃掉任何损坏的括号。如果您对格式了解更多,您可以进一步缩小范围

还要注意,这个正则表达式假定最后一个)instX之间的注释匹配[^\n]*\s*,并且它将接受括号内没有括号的任何内容

请您尝试以下方法:

#op = re.findall(r'^\s*(\w+)\s*$\n(?:^\s*[#/.].*$\n)*^\s*(\w+)\s*\(', a, re.MULTILINE)
op = re.findall(r'^\s*(\w+)\s*$\n(?:^\s*[^\w\s].*$\n)*^\s*(\w+)\s*\(', a, re.MULTILINE)
for i in op:
    print(i)

输出:

('block1', 'inst1')
('block2', 'inst2')
  • ^\s*(\w+)\s*$\n与块名行匹配
  • (?:^\s*[^\w\s].*$\n)*与参数行匹配
  • ^\s*(\w+)\s*\(与实例名称行匹配

请注意,我已经禁用了re.DOTALL选项(尽管解决这个问题很简单)

相关问题 更多 >