繁体   English   中英

python MULTILINE re.findall 在一个空行上拆分

[英]python MULTILINE re.findall spliting on one blank line

如果输入在我想要分隔的字符串部分之间有 2 个空行,我有一个成功的正则表达式。 但是如果只有一个空行,它就会失败。 你能建议吗?

我正在扫描一个大文件夹的类定义文件。 这是一个按预期工作的示例,它注意到 2 个类并将它们分开。

classstr = """class friendly():
    def __init__(x, y, z):
        self.x = x
        self.y = y
        self.z = z

    def printme(): 
        print(self.x)


class unfriendly():
    def friendme():
        assert self.x == self.y
"""
y = re.findall(r'^(class\s.*)((?:\n^\s.+)+)', classstr, re.MULTILINE)

输出是一个包含两个元组的列表,每个类一个。

In [15]: y
Out[15]: 
[('class friendly():',
  '\n    def __init__(x, y, z):\n        self.x = x\n        self.y = y\n        self.z = z'),
 ('class unfriendly():',
  '\n    def friendme():\n        assert self.x == self.y')]

如果输入classstr更改为在类之间只有一个空白行(示例代码中经常出现这种情况),那么整个代码块将返回一个 blob 元组:

[('class friendly():',
  '\n    def __init__(x, y, z):\n        self.x = x\n        self.y = y\n        self.z = z\n\n    def printme():\n        print(self.x)\n\nclass unfriendly():\n    def friendme():\n        assert self.x == self.y')]

显然,我无法理解如何在单个空行上终止 re。

建议?

有几点需要注意:

  • 使用\\s也可以匹配换行符
  • 在您的模式中,您使用\\n^\\s.+意味着下一行应包含至少 2 个字符,或换行符和至少包含一个字符的行

如果中间有 1 个空行,它将匹配下一部分,因为\\n\\s将匹配换行符,而.+将匹配该行的其余部分。

当有 2 个空行时它不起作用,因为\\n将匹配第一个空行,然后\\s将匹配第二个换行符但.+无法匹配,因为该行为空。

您可以做的是匹配所有不以class开头的行,并使整行*的量词也匹配中间的空行。

^(class[^\S\n].*)((?:\n(?!class ).*)+)
  • ^字符串开始
  • (捕获组 1
    • class[^\\S\\n].*匹配类后跟一个没有换行符的空白字符和该行的其余部分
  • )关闭第 1 组
  • (捕获组 2
    • (?:非捕获组(整体重复)
      • \\n(?!class ).*匹配一个换行符并断言该行不以class开头
    • )+关闭非捕获组并重复至少 1+ 次
  • )关闭第 2 组

正则表达式演示

我在应用接受的答案时发现了一些麻烦。 该解决方案确实解决了我提出的问题,但实际上我正在筛选的文件包含除类之外的其他代码。 因此,如果类后面有一个def ,给定的代码将在前一个类的输出中包含函数定义(因为 re` 正在逐行查找以除“类”以外的任何内容开头的行以确定包含)。

例如, re狼吞虎咽的def amorous在这里:

classstr = """class friendly():
    def __init__(x, y, z):
        self.x = x
        self.y = y
        self.z = z

    def printme():
        print(self.x)


class unfriendly():
    def friendme():
        assert self.x == self.y

def amorous():
    x = 3
"""

为了避免这种情况,我调整了解决方案中的re以包含所有不以字符开头的新行,而不是包含所有不以“class”开头的行。

y = re.findall(r'^(class[^\S\n].*)((?:\n(?!\S+).*)+)', classstr,
                   re.MULTILINE)
y2 = ["".join(i) for i in y]

输出很好,至少在这个例子中是这样。

>>> pprint(y2, compact=True)
['class friendly():\n'
 '    def __init__(x, y, '
 'z):\n'
 '        self.x = x\n'
 '        self.y = y\n'
 '        self.z = z\n'
 '\n'
 '    def printme():\n'
 '        print(self.x)\n'
 '\n',
 'class unfriendly():\n'
 '    def friendme():\n'
 '        assert self.x == self.y\n']

我在等着看这个修订会导致什么其他不良影响:)

同时,我还从这一变化中发现了其他一些好处。 使用类似的re来分隔def函数声明效果很好,即使对于嵌套函数也是如此。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM