2015-12-07 38 views
1

所以目前这个字符串:为什么perl正则表达式不像我所需要的那样贪婪?

!NAME: "Slot 10 SubSlot 0" 

有可能是最后的引号后一些东西,但这是无关手头的任务。

我的目标是,我想捕获插槽后的所有内容,直到最后一个引号出现为止。

我已经尝试了两种正则表达式的任务

/^!NAME:\s+\".*(Slot[\w|\s|\d+]+)\"/; 

另:

/^!NAME:\s+\".*(Slot.+)\"/; 

但这些仅捕获

Slot 0 

什么来后插槽可以完全不同。它可以是任何东西,如:

'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' 

,我们肯定知道的唯一的事情是,我们希望将“老虎”,开头,并且部分将用引号结束。其他任何东西都在空中。

我所显示的是什么问题?特别是第二个,因为我认为'。'运营商是贪婪的,会尽可能多地捕获?

该脚本的目的是捕获这些细节以便在另一个程序中解析。

+1

因为'。*'是贪婪的,所以你得到的“Slot”是最后一个。使用regex101.com测试您的模式,并使用调试器查看会发生什么。 –

+0

你为什么要逃避双引号?这在Perl正则表达式中不需要。 –

回答

2

这是贪婪。

/^!NAME:\s+\".*(Slot[\w|\s|\d+]+)\"/; 
      ^^ 
       |----- The greedy part is here. 

因为你的目标字符串匹配Slot \d+在两个地方,在.*报价吸食了第一个之后。尝试使表达的那部分非贪婪:

/!NAME:\s+\".*?(Slot(?:\w|\s|\d+)+)\"/ 
+0

'(?:\ w | \ s | \ d +)+'? '[\ W \ S \ d] +'! – ikegami

+0

我强烈建议不要使用非贪婪作为任何事情,而是优化。考虑你的解决方案如何处理'!NAME:“Slot 4 x!SubSlot 14 External”'。它不会拒绝匹配,它会看到'Slot 14 External'' – ikegami

1

这应该捕捉一切,这不是插槽后,但在报价之前出现报价:

/^!NAME:\s+\"Slot([^\"]*)\"/ 

,并纳入如果你插槽部分需要它由于某种原因

/^!NAME:\s+\"(Slot[^\"]*)\"/ 
+0

这不会捕获最初的'Slot',只会发生什么。 –

+0

是的,这就是他说他想要的第四行问题*耸耸肩* – dtanders

+0

啊,我明白了。好眼睛。 –

0

这适用于所有的示例文本:

^!NAME:\s*"(Slot.*?)" 

https://regex101.com/r/hB1cT3/2

注意:您所有的例子仅仅包含在报价中,除了“老虎”的文字,那你为什么在.*将作为报价的第一件事?正如暴徒所说的那样,这是造成问题的原因。我在这里删除了它。

0

这里有一个简单的解决方案:

/(Slot[^"]+)/ 

这是在行动:

my $s = '!NAME: "Slot 10 SubSlot 0"'; 
$s =~ /(Slot[^"]+)/; 
print $1; 

# Slot 10 SubSlot 0 

如果需要指定该行以!NAME:,然后只需将它扩展成:

/^!NAME:\s"(Slot[^"]+)/ 
1

最安全的答案:

/^ !NAME: \s* " (?:(?!Slot).)* Slot ([^"]*) "/x 

你也可以确保Slot没有一个字的一部分:

/^ !NAME: \s* " (?:(?!Slot).)* \b Slot \b ([^"]*) "/x 

诀窍是知道(?:(?!STRING).)*STRING[^CHAR]*CHAR

+0

示例数据没有双引号,但我认为这是最好的答案。 –

+0

@Hunter McMillen,唯一完整的示例文本有双引号。另外,解释说要匹配直到报价,并且OP的尝试包括双引号。 – ikegami