正则表达式 returns 第一个和最后一个匹配项,而不是返回匹配括号之间的第一个和第二个匹配项
regex returns first and last match instead of returning first and second match inbetween matching parenthesis
我正在尝试解析文本以提取所需的字符串。我在 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)
它没有return任何东西。它应该 returned 以下内容:
('except_check', 'data_check')
('abc', 'mask')
问题是 .*
匹配得尽可能 多 (贪婪)并且 re.DOTALL
它将尽可能少地匹配你的整个字符串仍然完全匹配 .
(\w+)\s*(#\(.*\))?.*?(\w+)\s*\(
^^ this one
基本上任何带有 .*
的正则表达式(如果允许 .
捕获真正的所有内容)将只匹配一次或根本不匹配,因为它能够匹配正则表达式的其余部分可以匹配的任何内容还有。
仅使用 .*?
也无法解决此问题,因为:
字符串的另一个问题是括号。正则表达式(没有一些花哨的扩展)只能匹配具有有限嵌套的括号。假设 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)*
匹配参数 lines
^\s*(\w+)\s*\(
匹配实例名称行
请注意我已经禁用了 re.DOTALL
选项(尽管解决这个问题很简单)。
如果第二组的单词字符在 2 个右括号之后,您可以省略 re.DOTALL
并使用例如尽可能少地使用 [\s\S]*?
匹配跨越多行的模式直到你遇到 2 个连续的括号。
此模式基于示例数据,可能容易出错,因为它依赖于 2 个括号作为块 2 之前的最后部分。
^\s*(\w+)\r?\n\s*#\([\s\S]*?\)\s*\).*\r?\n\s*(\w+)
另一个选项可能是匹配第一个块之后不以单词字符开头的行,并在第 2 组中捕获以单词字符开头的行的单词字符。
^\s*(\w+)\r?\n[^\S\r\n]*#\(.*(?:\r?\n(?![^\S\r\n]*\w).*)*\r?\n[^\S\r\n]+(\w+)
我正在尝试解析文本以提取所需的字符串。我在 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)
它没有return任何东西。它应该 returned 以下内容:
('except_check', 'data_check')
('abc', 'mask')
问题是 .*
匹配得尽可能 多 (贪婪)并且 re.DOTALL
它将尽可能少地匹配你的整个字符串仍然完全匹配 .
(\w+)\s*(#\(.*\))?.*?(\w+)\s*\(
^^ this one
基本上任何带有 .*
的正则表达式(如果允许 .
捕获真正的所有内容)将只匹配一次或根本不匹配,因为它能够匹配正则表达式的其余部分可以匹配的任何内容还有。
仅使用 .*?
也无法解决此问题,因为:
字符串的另一个问题是括号。正则表达式(没有一些花哨的扩展)只能匹配具有有限嵌套的括号。假设 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)*
匹配参数 lines^\s*(\w+)\s*\(
匹配实例名称行
请注意我已经禁用了 re.DOTALL
选项(尽管解决这个问题很简单)。
如果第二组的单词字符在 2 个右括号之后,您可以省略 re.DOTALL
并使用例如尽可能少地使用 [\s\S]*?
匹配跨越多行的模式直到你遇到 2 个连续的括号。
此模式基于示例数据,可能容易出错,因为它依赖于 2 个括号作为块 2 之前的最后部分。
^\s*(\w+)\r?\n\s*#\([\s\S]*?\)\s*\).*\r?\n\s*(\w+)
另一个选项可能是匹配第一个块之后不以单词字符开头的行,并在第 2 组中捕获以单词字符开头的行的单词字符。
^\s*(\w+)\r?\n[^\S\r\n]*#\(.*(?:\r?\n(?![^\S\r\n]*\w).*)*\r?\n[^\S\r\n]+(\w+)