Python 正则表达式获得唯一的多行匹配
Python Regex get Unique Multiline Matches
由于背景解释起来很复杂,我正在编写伪代码,
我只对 Python-Regex-Pattern 感兴趣,希望你们中的一个能帮助我
我有以下输入文本(很多行 \n
作为行分隔符压缩为 '.'):
.
.
1 Order
order1 stuff
order1 stuff
etc
ShippingMethod: Truck
.
.
2 Order
order2 stuff
order2 stuff
etc
ShippingMethod: Truck
.
.
Order Summary
.
.
我只想为每个订单单独匹配 'Order' 和 'Truck' 之间的文本 ,然后我会进一步迭代结果程序。
我的正则表达式:(为了更好的可读性,我分为“开始、内容、结束”)。
pattern = \d\s*Order + [.|\s|\S]* + Truck
当我执行这场比赛时,我得到一个结果,从 1 Order
开始到 秒 Truck
:
1 Order
order1 stuff
order1 stuff
etc
ShippingMethod: Truck
.
.
2 Order
order2 stuff
order2 stuff
etc
ShippingMethod: Truck
我想要(在这种情况下)恰好两个 只包含一个订单内容的匹配项:
1 Order
order1 stuff
order1 stuff
etc
ShippingMethod: Truck
2 Order
order2 stuff
order2 stuff
etc
ShippingMethod: Truck
希望您清楚我在寻找什么。非常感谢任何帮助。
提前致谢,注意安全,保持健康!
您可能会建议的事情:
- 您必须假设行首和单词之间有不同数量的空格,因为输入文本是 PDF 文本提取器的结果。但是 \n 是可以信任的。基本上是写 \n 写 \s*\n
- 我不能使用“订单”作为模式的结尾部分,因为在最后一个订单之后接下来就是摘要。
- “ShippingMethod”在我的语言中有所不同,这就是为什么我在此处的示例中使用“卡车”。我会设法重写。
解决方案看似简单 - 使用非贪婪运算符 ?
。
首先,字符 class 正则表达式 []
匹配其中的任何字符,因此要匹配 a
和 b
正则表达式是 [ab]
而不是 [a|b]
。所以你代码的 content 部分应该是 [.\s\S]
.
此外,\s
和 \S
匹配所有 space s 和非 spaces,因此句点 (.
) 与此处无关。
所以最后的内容部分应该是这样的:[\s\S]*
现在是实际解决方案:
贪婪的 ?
运算符在任何正常频率运算符(如 +
、*
和 ?
之后告诉正则表达式匹配 作为少数element/s尽可能。使用 *
,您使用的是 零或更多 的默认贪婪版本,告诉正则表达式匹配尽可能多的(最终甚至匹配第一个 Truck
你想要!)
所以我们在末尾添加了一个非贪婪运算符,因此最终的正则表达式如下所示:
\d\s*Order[\s\S]*?Truck
奖金建议:
字符 class [\s\S]
是告诉正则表达式匹配每个字符的巧妙方法(因为每个字符要么是 space 要么不是 space) .但事实证明,有一种方法可以通过使用 re.DOTALL
修饰符来提高效率。它按照它说的做 - 它告诉正则表达式 .
(DOT)应该匹配所有字符,包括换行符。
如果这是您使用的代码:
re.findall(r'\d\s*Order[\s\S]*?Truck', input_text)
这是最好的代码(包括问题的解决方案):
re.findall(r'\d\s*Order.*?Truck', input_text, re.DOTALL)
如您所见,.*?
现在将匹配从 Order
到 Truck
的所有内容(包括换行符)。
不使用re.DOTALL,如果Truck
不存在,防止过度匹配,您可以使用:
^\d+\s*Order\b.*(?:\n(?!\d+\s* Order\b|.* Truck$).*)*\n.* Truck$
模式匹配:
^
字符串开头
\d+\s*Order\b.*
匹配数字后跟 Order
和行的其余部分
(?:
非捕获组
\n(?!\d+\s* Order\b|.* Truck$)
匹配换行符并断言该行不以数字开头和 Order
并断言该行不以 Truck
结尾
.*
如果断言为真,匹配整行
)*
关闭非捕获组以匹配所有行
\n.* Truck$
匹配换行符和以 Truck
结尾的行的其余部分
import re
regex = r"^\d+\s*Order\b.*(?:\n(?!\d+\s* Order\b|.* Truck$).*)*\n.* Truck$"
s = ("\n\n"
"1 Order \n"
"order1 stuff\n"
"order1 stuff\n"
"etc\n"
"ShippingMethod: Truck\n\n\n"
"2 Order\n"
"order2 stuff\n"
"order2 stuff\n"
"etc\n"
"ShippingMethod: Truck\n\n\n"
"Order Summary\n\n")
print(re.findall(regex, s, re.MULTILINE))
输出
['1 Order \norder1 stuff\norder1 stuff\netc\nShippingMethod: Truck', '2 Order\norder2 stuff\norder2 stuff\netc\nShippingMethod: Truck']
由于背景解释起来很复杂,我正在编写伪代码, 我只对 Python-Regex-Pattern 感兴趣,希望你们中的一个能帮助我
我有以下输入文本(很多行 \n
作为行分隔符压缩为 '.'):
.
.
1 Order
order1 stuff
order1 stuff
etc
ShippingMethod: Truck
.
.
2 Order
order2 stuff
order2 stuff
etc
ShippingMethod: Truck
.
.
Order Summary
.
.
我只想为每个订单单独匹配 'Order' 和 'Truck' 之间的文本 ,然后我会进一步迭代结果程序。
我的正则表达式:(为了更好的可读性,我分为“开始、内容、结束”)。
pattern = \d\s*Order + [.|\s|\S]* + Truck
当我执行这场比赛时,我得到一个结果,从 1 Order
开始到 秒 Truck
:
1 Order
order1 stuff
order1 stuff
etc
ShippingMethod: Truck
.
.
2 Order
order2 stuff
order2 stuff
etc
ShippingMethod: Truck
我想要(在这种情况下)恰好两个 只包含一个订单内容的匹配项:
1 Order
order1 stuff
order1 stuff
etc
ShippingMethod: Truck
2 Order
order2 stuff
order2 stuff
etc
ShippingMethod: Truck
希望您清楚我在寻找什么。非常感谢任何帮助。
提前致谢,注意安全,保持健康!
您可能会建议的事情:
- 您必须假设行首和单词之间有不同数量的空格,因为输入文本是 PDF 文本提取器的结果。但是 \n 是可以信任的。基本上是写 \n 写 \s*\n
- 我不能使用“订单”作为模式的结尾部分,因为在最后一个订单之后接下来就是摘要。
- “ShippingMethod”在我的语言中有所不同,这就是为什么我在此处的示例中使用“卡车”。我会设法重写。
解决方案看似简单 - 使用非贪婪运算符 ?
。
首先,字符 class 正则表达式 []
匹配其中的任何字符,因此要匹配 a
和 b
正则表达式是 [ab]
而不是 [a|b]
。所以你代码的 content 部分应该是 [.\s\S]
.
此外,\s
和 \S
匹配所有 space s 和非 spaces,因此句点 (.
) 与此处无关。
所以最后的内容部分应该是这样的:[\s\S]*
现在是实际解决方案:
贪婪的 ?
运算符在任何正常频率运算符(如 +
、*
和 ?
之后告诉正则表达式匹配 作为少数element/s尽可能。使用 *
,您使用的是 零或更多 的默认贪婪版本,告诉正则表达式匹配尽可能多的(最终甚至匹配第一个 Truck
你想要!)
所以我们在末尾添加了一个非贪婪运算符,因此最终的正则表达式如下所示:
\d\s*Order[\s\S]*?Truck
奖金建议:
字符 class [\s\S]
是告诉正则表达式匹配每个字符的巧妙方法(因为每个字符要么是 space 要么不是 space) .但事实证明,有一种方法可以通过使用 re.DOTALL
修饰符来提高效率。它按照它说的做 - 它告诉正则表达式 .
(DOT)应该匹配所有字符,包括换行符。
如果这是您使用的代码:
re.findall(r'\d\s*Order[\s\S]*?Truck', input_text)
这是最好的代码(包括问题的解决方案):
re.findall(r'\d\s*Order.*?Truck', input_text, re.DOTALL)
如您所见,.*?
现在将匹配从 Order
到 Truck
的所有内容(包括换行符)。
不使用re.DOTALL,如果Truck
不存在,防止过度匹配,您可以使用:
^\d+\s*Order\b.*(?:\n(?!\d+\s* Order\b|.* Truck$).*)*\n.* Truck$
模式匹配:
^
字符串开头\d+\s*Order\b.*
匹配数字后跟Order
和行的其余部分(?:
非捕获组\n(?!\d+\s* Order\b|.* Truck$)
匹配换行符并断言该行不以数字开头和Order
并断言该行不以Truck
结尾
.*
如果断言为真,匹配整行
)*
关闭非捕获组以匹配所有行\n.* Truck$
匹配换行符和以Truck
结尾的行的其余部分
import re
regex = r"^\d+\s*Order\b.*(?:\n(?!\d+\s* Order\b|.* Truck$).*)*\n.* Truck$"
s = ("\n\n"
"1 Order \n"
"order1 stuff\n"
"order1 stuff\n"
"etc\n"
"ShippingMethod: Truck\n\n\n"
"2 Order\n"
"order2 stuff\n"
"order2 stuff\n"
"etc\n"
"ShippingMethod: Truck\n\n\n"
"Order Summary\n\n")
print(re.findall(regex, s, re.MULTILINE))
输出
['1 Order \norder1 stuff\norder1 stuff\netc\nShippingMethod: Truck', '2 Order\norder2 stuff\norder2 stuff\netc\nShippingMethod: Truck']