【问题标题】:regex + shortest substring + word preceded by another word正则表达式 + 最短子字符串 + 前面有另一个单词的单词
【发布时间】:2015-05-05 17:14:21
【问题描述】:

我有下面的例子

"foo 告诉 bar bar 喜欢土豆。bar 告诉 foo bar 不喜欢 像土豆一样。”

我想要土豆和之前出现的 bar 之间的子字符串。所以在这个例子中,我想要“酒吧喜欢土豆”,也想要“酒吧不喜欢土豆”作为结果。如何通过一个正则表达式实现这一目标?我知道如果我应用两个单独的正则表达式,我可以获得结果,但我想知道这是否可能只使用一个正则表达式。

谢谢, RG

【问题讨论】:

标签: regex lookahead negative-lookahead


【解决方案1】:

很好的谜语。可以解决,只是方式不是很好:

echo "Foo tells bar that bar likes potato. Bar tells foo that bar does not like potato." | \
    pcregrep  -o '\bbar\s+(?:(?:(?!bar\b)\w+)\s+)*?potato\b'

外部(?:...) 匹配一个后跟一个空格的单词。内部确保所说的词不是bar

【讨论】:

  • 也可以。谢谢!
  • 分隔单词字符的好主意,(要遵循相同的想法,您应该将 \s 替换为 \W 并在开头和结尾添加单词边界。)
  • 用 \b 排除“foobar ...土豆”
  • @Deadooshka 是的,已编辑。我只是不想再掩盖正在发生的事情。
【解决方案2】:

Python试试这个:

>>> import re
>>> s = "Foo tells bar that bar likes potato. Bar tells foo that bar does not like potato."
>>> re.findall('bar (?:(?! bar ).)+? potato', s)
['bar likes potato', 'bar does not like potato']

【讨论】:

  • 工作就像一个魅力!您能否解释一下内部循环“(?:(?!bar)。)”在这种情况下是如何工作的?
  • @user3669040 (?:...) 是常规括号的非捕获版本(括号用于分组)。 (?!...) 是一个否定的前瞻断言,即,Isaac (?!Asimov) 将匹配 Isaac ,仅当它后面没有 Asimov 时。
【解决方案3】:

这是可能的,如下 perl sn-p 所示:

use strict;
use warnings;

my $str
  = "Foo tells bar that bar likes potato. "
  . "Bar tells foo that bar does not like potato."
;

while ($str =~ m/( bar (?: [^b] | b[^a] | ba[^r] )*?  potato )/xmsg) {
    print STDOUT "$1\n";
}

*? 是一个非贪婪的量词(匹配 0 次或多次,不是贪婪的;参见 http://perldoc.perl.org/perlre.html 的量词)

请注意,备选方案[^b] | b[^a] | ba[^r] 是互斥的。如果您想了解有关此类结构的更多信息,“掌握正则表达式”(http://regex.info/)一书非常有指导意义。

【讨论】:

  • 这行得通,但是将其扩展到更长的单词会变得越来越复杂。正如我在回答中所做的那样,您可以通过负面的前瞻性来避免这种情况。诀窍是在两端锚定前瞻以使其有效。
  • 确实,您的解决方案执行得更好(大约快两倍)。但是,它确实假设用空格分隔的单词(我的没有);因为这是一个可能的假设,所以我更喜欢你的假设。可以简化一点:bar\s+(?>(?!bar\b)\w+\s+)*?potato
  • @Loic:我会这样写:\bbar\W+(?:(?!bar\b)\w+\W+)*?potato\b (回溯考虑不需要原子组,因为你使用惰性量词前进)
  • @Loic:是的,对于我的解决方案,必须在负前瞻的两端都使用一些东西作为锚点,这才是问题的真正症结。
  • @Casimir et Hippolyte:这不是真的,非贪婪量化并不能确保量化的组被原子处理。例如,字符串"aa"(?:a*)*?a 接受,但不被(?>a*)*?a 接受;因此回溯发生在第一个正则表达式中。一般来说,我更喜欢尽可能避免嵌套量化,因为它们可能在病理输入上表现不佳(并非总是如此,但仍然存在风险)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多