请考虑以下文本:
SELECT
CAST(POS.BALANCE AS DECIMAL(18, @currencyround)) AS DBAmount
FROM
dbo.POS_SALES POS
您可能已经猜到了,我想从每个部分中提取!
interesting1 a
not interesting b
interesting2 c
!
interesting1 a
not interesting b
interesting2 c
!
interesting1 a
not interesting b
interesting2 c
not interesting arbitrary text d
!
和a
。 c
行是可选的,但是如果也有interesting2 c
(按节),我只需要a
。
使用c
我得到:
!\n(interesting1 (?P<a>.*?)$.*?(?:interesting2 (?P<c>.*?))?$\n(?=!))
和a
来自最前面的两个部分,但(可以理解)来自最后一个部分的c
和a
。请参见regex101。
我怀疑这是在这种情况下最有效的正则表达式,因为这小段文字需要438个步骤,因此我愿意接受任何其他更有效的解决方案以获取正确的结果。
如果我将正则表达式更改为c\nnot interesting arbitrary text d
(而不是捕获组!\n(interesting1 (?P<a>.*?)$.*?(?:interesting2 (?P<c>\w+))?$\n(?=!))
中的\w+
的{{1}}),则它在第三部分匹配的唯一内容是{{1} }(由于.*?
不包含c
,因此可以预期。)
我不了解如何使用a
来指定
\w
和结束\n
之间的任意文本的可选行。
使用可选的非捕获组和$
的不同变体形式不能给我正确的结果。我什至在前瞻部分中尝试了可选的非捕获组(以表示我们在!之前可能还有其他/可选的内容)。
答案 0 :(得分:1)
我用这个
import re
text=\
"""
!
interesting1 a
not interesting b
interesting2 c
!
interesting1 a
not interesting b
interesting2 c
!
interesting1 a
not interesting b
interesting2 c
not interesting d
!
"""
pa = re.compile(r'^interesting[12] ([a-zA-Z]){1}', re.MULTILINE)
m = pa.findall(text)
print(m)
它有6个算数,128个步骤。
答案 1 :(得分:1)
我不了解如何使用
$
来指定interesting2 c
和结束!
之间的任意文本的可选行。
这是因为$
与匹配可选的文本行无关。 $
只是一个锚,它在字符串的末尾(如果正则表达式处于多行模式,则在换行符之前)声明一个位置。完全不需要匹配一行文本。
您的正则表达式无法正常工作的原因非常简单:缺少与可选行匹配的内容。正如我之前说过的,$
只是一个锚点-它不会使用任何文本。因此,为了成功匹配您的(?=!)
前瞻,组c
必须增长并匹配所有文本,直到!
字符为止。为了防止这种情况的发生,您必须添加可以匹配最后一行的内容,例如.*?
或[^\n]*
。
但是,在这种特定情况下,这并不像在.*?
前行添加(?=!)
那样简单。为什么?由于c
组是可选的,因此在末尾添加.*?
将阻止c
组的匹配:
!\n(interesting1 (?P<a>.*?)$.*?(?:interesting2 (?P<c>\w+))?$\n.*?(?=!))
^ ^ ^
| | this .*? would grow
| | and consume the
| | "interesting2 c"
| this group is optional, so it would be skipped
this .*? would match the empty string
因此,最好是从头开始重写正则表达式。
这是我的写法:
!\ninteresting1 (?P<a>.*)(?:\n[^!].*)*\ninteresting2 (?P<c>.*)
逻辑很简单:
!\ninteresting1 (?P<a>.*)
匹配第一行并捕获a
(?:\n[^!].*)*
跳过所有以!
开头的行\ninteresting2 (?P<c>.*)
匹配并捕获c
这与您的正则表达式略有不同,因为仅当a
和c
同时存在于一个节中时,它才会产生匹配项。另请参见online demo。