【问题标题】:Can someone please explain the greediness in this regex有人可以解释一下这个正则表达式的贪婪吗
【发布时间】:2012-06-20 15:17:16
【问题描述】:

我有一些文本,其中每一行文本都有一些好词和一些坏(不需要的)词。所以模式可能看起来像这样

good1-good2 good3 bad1-good4-bad2 some more good words
good1-good2 good3 bad1 bad2 
good1-good2 good3 bad1 bad2 bad3

现在我需要拒绝一行中的所有内容,包括第一个坏词 所以

good1-good2 good3 bad1-good4-bad2 some more good words 应该变成good1-good2 good3

good1-good2 good3 bad1 bad2 应该变成good1-good2 good3

good1-good2 good3 bad1 bad2 bad3 应该变成good1-good2 good3

我正在使用 python,所以这就是我所做的

p=re.compile('([\w \d-]+) (bad1|bad2|bad3).+',re.I)
m=p.search('good1-good2 good3 bad1-good4-bad2 ')
m.group(1)

这给了good1-good2 good3 这是我想要的,但是

m=p.search('good1-good2 good3 bad1 bad2 ')
m.group(1)

返回good1-good2 good3 bad1 我认为因为+ 是贪婪的,所以([\w \d-]+) 中的+ 继续匹配字符直到行尾,然后它回溯以找到最后一个坏词,在这种情况下是bad2 但是当我这样做

p=re.compile('([\w \d-]+) (bad1|bad2|bad3).+',re.I)
m=p.search('good1-good2 good3 bad1 bad2 bad3')
m.group(1)

它再次返回good1-good2 good3 bad1。 你能解释一下吗?因为我在正则表达式中对greediness 的理解可能有问题?虽然我已经想办法解决这个问题 通过使用像 ([\w \d-]+?) (bad1|bad2|bad3).+ 这样的正则表达式,但我仍然不明白为什么使用 ([\w \d-]+) (bad1|bad2|bad3).+ 总是返回第一个坏词(在这种情况下是 bad1)?

感谢您的时间。

编辑: 但是假设我有一个只有好词没有坏词的模式 good1-good2 good3--only good words 那么正则表达式应该是什么? 我试过这个正则表达式([\w \d-]+?) ?(bad1|bad2|bad3)?.*,但这会返回模式的第一个字母。

【问题讨论】:

  • 第一个子模式也是贪婪的,所以它得到了它可以匹配的最多,然后是第二个,等等......
  • @poncha 我的问题是第三种情况。为什么当我查看good1-good2 good3 bad1 bad2 bad3 时它返回good1-good2 good3 bad1?按照我对贪婪的理解应该是返回了good1-good2 good3 bad1 bad2

标签: regex regex-greedy


【解决方案1】:

关于这个案例:

m=p.search('good1-good2 good3 bad1 bad2 ')

你是对的。 ([\w \d-]+) 是贪婪的,所以它会尽可能多地“吃掉”并回溯。

然而,关于这种情况:

m=p.search('good1-good2 good3 bad1 bad2 bad3')

您可能没有看到的是,您的.+ 必须匹配在坏词之后至少一个字符。这就是为什么正则表达式不能将bad3 匹配为坏词:如果匹配,它将用完字符,.+ 无法匹配任何内容。因此,它再次回溯到bad2。将您的 .+ 更改为 .* 以查看差异。只是因为您在第一种情况下碰巧有一个额外的空间,bad2 ,那里的事情“按预期工作”。

换句话说,一些不幸的巧合让你感到困惑;但你对贪婪的理解是正确的。

编辑

对于问题的已编辑部分,由以下 cmets 的@lovesh 撰写:

([\w \d-]+?) ?(bad1|bad2|bad3|$)

【讨论】:

  • 我知道我已经接受了你的回答,但我才意识到我错过了一些东西。我已经编辑了我的问题。你能帮忙吗?谢谢
  • 在您的编辑中,它只返回第一个字母,因为您使第一部分不贪心,即([\w \d-]+?),因此它只需要匹配一个字母,而.* 则占据其余部分.我一直在考虑解决方案,但这实际上是一个棘手的问题……我会尽快回复您。
  • 同时,我不得不问,你这样做是绝对必要的吗?比如,你不能直接匹配bad1|bad2|bad3|...,然后用m.start()得到第一个坏词的索引,然后从那个索引中剪掉原来的字符串吗?
  • 我想我明白了。 ^(.*?)(?=bad1|bad2|bad3|$)。你可以在这里看到它的实际效果:rubular.com/r/Ai1a96xPks。它基本上说,“最短的字符串后跟一个坏词或行尾。” $ 必须是备用列表中的最后一个才能正常工作。
  • 谢谢。那很聪明。但我认为你不需要前瞻。我试过这个 ([\w \d-]+?)(bad1|bad2|bad3|$)group(1) 作品
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多