为什么 perl 正则表达式不像我需要的那样贪婪?
Why isn't the perl regex being as greedy as I need it to be?
所以显示这个字符串:
!NAME: "Slot 10 SubSlot 0"
最后一个引号后面可能有一些内容,但这与手头的任务无关。
目标是,我想捕获 Slot UP 之后的所有内容,直到最后的引号。
我已经为任务尝试了两个正则表达式
/^!NAME:\s+\".*(Slot[\w|\s|\d+]+)\"/;
其他:
/^!NAME:\s+\".*(Slot.+)\"/;
但这些只捕获
Slot 0
Slot 之后的内容可能截然不同。它可能是这样的:
'Slot 4' (this works, but the capture string will not always be this small)
'Slot 4 Subslot 12 Internal Subslot 14 External'
'Slot 75 Internal Slot 12 External'
我们唯一确定的是我们想要的部分将以 'Slot' 开头,并以引号结尾。介于两者之间的任何其他事情都悬而未决。
我展示的有什么问题吗?尤其是第二个,因为我认为“。”运营商很贪婪,会尽可能多地捕获?
此脚本的目的是捕获这些细节以在另一个程序中进行解析。
贪婪。
/^!NAME:\s+\".*(Slot[\w|\s|\d+]+)\"/;
^^
|----- The greedy part is here.
由于您的目标字符串在两个地方与 Slot \d+
匹配,因此引号后的 .*
吞掉了第一个。尝试使表达式的那部分成为非贪婪的:
/!NAME:\s+\".*?(Slot(?:\w|\s|\d+)+)\"/
这应该捕获不是在 Slot 之后但在引号之前的引号的所有内容:
/^!NAME:\s+\"Slot([^\"]*)\"/
如果您出于某种原因需要它,还可以包含 Slot 部分
/^!NAME:\s+\"(Slot[^\"]*)\"/
这适用于您的所有示例文本:
^!NAME:\s*"(Slot.*?)"
https://regex101.com/r/hB1cT3/2
注意:除了 "Slot" 文本外,您所有的示例都不包含任何引号,那么为什么要将 .*
作为引号中的第一部分?正如暴民上面提到的,这就是造成问题的原因。我已经把它删除了。
这是一个简单的解决方案:
/(Slot[^"]+)/
这是实际操作:
my $s = '!NAME: "Slot 10 SubSlot 0"';
$s =~ /(Slot[^"]+)/;
print ;
# Slot 10 SubSlot 0
如果需要指定以!NAME:
开头的行,那么就展开成这样:
/^!NAME:\s"(Slot[^"]+)/
最安全的答案:
/^ !NAME: \s* " (?:(?!Slot).)* Slot ( [^"]* ) "/x
您还可以确保 Slot
不是另一个词的一部分:
/^ !NAME: \s* " (?:(?!Slot).)* \b Slot \b ( [^"]* ) "/x
诀窍是知道 (?:(?!STRING).)*
是 STRING
就像 [^CHAR]*
是 CHAR
.
所以显示这个字符串:
!NAME: "Slot 10 SubSlot 0"
最后一个引号后面可能有一些内容,但这与手头的任务无关。
目标是,我想捕获 Slot UP 之后的所有内容,直到最后的引号。
我已经为任务尝试了两个正则表达式
/^!NAME:\s+\".*(Slot[\w|\s|\d+]+)\"/;
其他:
/^!NAME:\s+\".*(Slot.+)\"/;
但这些只捕获
Slot 0
Slot 之后的内容可能截然不同。它可能是这样的:
'Slot 4' (this works, but the capture string will not always be this small)
'Slot 4 Subslot 12 Internal Subslot 14 External'
'Slot 75 Internal Slot 12 External'
我们唯一确定的是我们想要的部分将以 'Slot' 开头,并以引号结尾。介于两者之间的任何其他事情都悬而未决。
我展示的有什么问题吗?尤其是第二个,因为我认为“。”运营商很贪婪,会尽可能多地捕获?
此脚本的目的是捕获这些细节以在另一个程序中进行解析。
贪婪。
/^!NAME:\s+\".*(Slot[\w|\s|\d+]+)\"/;
^^
|----- The greedy part is here.
由于您的目标字符串在两个地方与 Slot \d+
匹配,因此引号后的 .*
吞掉了第一个。尝试使表达式的那部分成为非贪婪的:
/!NAME:\s+\".*?(Slot(?:\w|\s|\d+)+)\"/
这应该捕获不是在 Slot 之后但在引号之前的引号的所有内容:
/^!NAME:\s+\"Slot([^\"]*)\"/
如果您出于某种原因需要它,还可以包含 Slot 部分
/^!NAME:\s+\"(Slot[^\"]*)\"/
这适用于您的所有示例文本:
^!NAME:\s*"(Slot.*?)"
https://regex101.com/r/hB1cT3/2
注意:除了 "Slot" 文本外,您所有的示例都不包含任何引号,那么为什么要将 .*
作为引号中的第一部分?正如暴民上面提到的,这就是造成问题的原因。我已经把它删除了。
这是一个简单的解决方案:
/(Slot[^"]+)/
这是实际操作:
my $s = '!NAME: "Slot 10 SubSlot 0"';
$s =~ /(Slot[^"]+)/;
print ;
# Slot 10 SubSlot 0
如果需要指定以!NAME:
开头的行,那么就展开成这样:
/^!NAME:\s"(Slot[^"]+)/
最安全的答案:
/^ !NAME: \s* " (?:(?!Slot).)* Slot ( [^"]* ) "/x
您还可以确保 Slot
不是另一个词的一部分:
/^ !NAME: \s* " (?:(?!Slot).)* \b Slot \b ( [^"]* ) "/x
诀窍是知道 (?:(?!STRING).)*
是 STRING
就像 [^CHAR]*
是 CHAR
.