我有这个正则表达式:
a_list = re.compile(r'\(\d+\)\s*\n').split(content)
最后匹配行与(数字)的效果很好,但是我也需要得到那个数字。
我怎么做?
谢谢。
使用split
函数可能需要后视断言,不幸的是后视需要固定宽度的模式(这就是@Thunderforge 尝试过的)。我的解决方案使用findall
:
re.findall(r'(.*?\(\d+\))\s*\n', content, re.S)
笔记:
re.S
使“。” 完全匹配任何字符,包括换行符.*?
表示非贪婪匹配但是这个解决方案仍然存在缺陷。如果content
不以数字和“\n”结尾,则最后一部分将被丢弃。我们可以通过列表推导或者生成器表达式来解决这个问题,即:
[i or j for i, j in re.findall(r'(.*?\(\d+\))\s*\n|(.+)', content, re.S)]
或者:
(i or j for i, j in re.findall(r'(.*?\(\d+\))\s*\n|(.+)', content, re.S))
如Python 的正则表达式文档中所述,正则表达式上的 split 方法会拆分正由正则表达式模式的所有匹配项处理的字符串。现在,您的正则表达式正在捕获所有末尾有数字的匹配项,并在该匹配项上拆分字符串。所以 a_list 包含每行中包含数字的所有内容,除了数字及其周围的括号(和可选空格)。
假设您不想拆分所有换行符(仅通过制作您的 regex '\n'
),您可以使用否定的lookbehind仅捕获与匹配之前另一个正则表达式的正则表达式的匹配,但不包括第二个正则表达式的匹配项结果。其格式是(?<!x)y
当且仅当 x 短语正在处理它时,y 的所有实例都将被捕获,但 x 短语不会与它一起包含。
在这种情况下使用否定后视的唯一问题是它需要匹配固定数量的字符,但是您有\d+
,它可以是任意数量的字符。幸运的是,您可以只删除+
前导\(
,以便检查正则表达式模式之前是否至少有一位数字,以便我们只检查\d\)
; 之所以有效,是因为我们不在乎该行是否以(10000)
or结尾(1)
。
不幸的是,这会导致像被捕获的行,这与您最初拥有的正则表达式(abc123)
不匹配。\(\d+\)
如果您需要确保行以仅包含多位数字的括号结尾,您可能必须使用多个正则表达式操作。
这确实留下了 的问题\s*
,因此您有两个选择。如果您知道末尾有多少个空格,您可以创建一个 or 表达式,例如(\d|\d\s)
,或者您可以只\s*
在匹配中包含换行符,从而也删除任何尾随空格。
假设您采用后一种选项,您的示例将如下所示(?<!\d\))\s*\n
,这将导致 a_list 包含所有在末尾包含数字的行,以及数字本身(及其周围的括号)。