2009-12-02 82 views
7

可以使用哪个正则表达式来查找所有字符串bar前面没有字符串foo?两者之间有空白也是非法的。如何找到一个单词之前没有另一个特定的单词?

所以,正则表达式应该采用以下

(?!<foo)bar 

符合下列字符串

foo is bar 
hello bar 

但不是这些

foobar 
foo  bar 

我试着和它得到所做的工作消除foobar,但我需要照顾的空白,当然

(?!<foo)\s*bar 

匹配所有字符串。

谢谢!

+1

“匹配所有字符串”。 - 迂回模式:(?! 2009-12-02 20:54:35

+0

您说得对,谢谢指出! 我结束了使用以下内容: preg_match('/(foo)?\ s * bar /',haystack,matches); 这将找到酒吧(无论前面是否有foo),然后对匹配[]进行快速检查将确定foo是否存在。 – Sleepster 2009-12-03 00:34:25

+0

您正在寻找的东西具体称为**零宽度负面后顾断言**。 Perl显然不支持可变宽度后视(正面或负面),所以像\ s *之类的东西在其中一个将不起作用。尝试使用多个匹配运算符。 – fennec 2009-12-30 05:25:54

回答

0
(?!<foo)\s*bar 

这将匹配空白

+0

呃没有。首先,它是'(?<!..)',其次,'\ s *'需要在lookbehind内部,否则它总是匹配,除非'foo'和'bar'之间没有空格。马克·拜尔斯说得对。 – 2009-12-02 21:43:45

+2

确定我所知道的是JA编辑我的答案,我感到有福。 – Hogan 2009-12-03 16:28:40

0

PHP:

!preg_match(/foo\s*bar/,$string) && preg_match(/bar/,$string) 

的Perl:

$string !~ /foo\s*bar/ && $string =~ /bar/ 
+0

正如原始问题中提到的,这不起作用。 – Sleepster 2009-12-02 20:49:54

+0

嗯,是的,因为所有的字符串在技术上都可以被发现在非酒吧串之前... – 2009-12-02 20:56:45

+0

你真正需要的是做一个负面的正则表达式。 $ string!〜/ foo \ s * bar /。用php和perl版本更新。 – 2009-12-02 21:02:30

2

鉴于一些测试用例

my @match = (
    "foo is bar", 
    "hello bar", 
); 

my @reject = (
    "foobar", 
    "foo  bar", 
); 

你当然可以做一个模式的结果输送到另一个:

my @control = grep !/foo\s*bar/, grep /bar/ => @match, @reject; 

我们也可以用一个做到这一点:

my $nofoo = qr/ 
    (  [^f] | 
    f (?! o) | 
    fo (?! o \s* bar) 
)* 
/x; 

my $pattern = qr/^ $nofoo bar /x; 

但是,不要把我的话。

for (@match) { 
    print +(/$pattern/ ? "PASS" : "FAIL"), ": $_\n"; 
} 

for (@reject) { 
    print +(/$pattern/ ? "FAIL" : "PASS"), ": $_\n"; 
} 
+0

令人印象深刻的是,你得到了这个工作。最有可能的“富”和“酒吧”只是更长的字符串的占位符。看起来你的正则表达式对于任何真实世界的例子都会变得非常长。尽管为不同的方法+1。 – 2009-12-02 23:28:17

+0

谢谢,可悲的消息是字面模式是最好的情况。我想知道这种方法的局限性是什么。对于这样的任务来说,有一个正则表达式开关可以补充每个NFA状态的接受状态。 – 2009-12-03 19:54:26

4

更好地使用编程语言的其他工具,而不是看看太正确的正则表达式模式。

您在查找$s =~ /bar/ and not $s =~ /foo\s*bar/为真的字符串。

以下脚本的其余部分仅用于测试。

#!/usr/bin/perl 

use strict; use warnings; 

my %strings = (
    'foo is bar' => 1, 
    'hello bar' => 1, 
    'foobar'  => 0, 
    'foo  bar' => 0, 
    'barbar'  => 1, 
    'bar foo'  => 1, 
    'foo foo'  => 0, 
); 

my @accept = grep { $strings{$_} } keys %strings; 
my @reject = grep { not $strings{$_} } keys %strings; 

for my $s (@accept) { 
    if ($s =~ /bar/ and not $s =~ /foo\s*bar/) { 
     print "Good: $s\n"; 
    } 
    else { 
     print "Bad : $s\n"; 
    } 
} 

for my $s (@reject) { 
    if ($s =~ /bar/ and not $s =~ /foo\s*bar/) { 
     print "Bad : $s\n"; 
    } 
    else { 
     print "Good: $s\n"; 
    } 
} 

输出:

 
E:\srv\unur> j 
Good: bar foo 
Good: hello bar 
Good: foo is bar 
Good: barbar 
Good: foo foo 
Good: foo  bar 
Good: foobar 
+0

即使字符串不包含“酒吧”,这不会匹配吗? – 2009-12-02 21:26:02

+0

@Mark Byers:谢谢你指出我的疏忽。固定。 – 2009-12-02 21:51:22

+1

'酒吧foobar'也使一个有趣的测试案例。虽然我不确定预期的输出是什么。 – 2009-12-02 22:30:15

0

以从早期的答案信息,包装作为一个Perl的一行,并使得正则表达式不区分大小写。

视窗:

perl -lne "print $_ if $_ !~ m/foo\s*bar/i && $_ =~ m/bar/i;" c:\temp\xx.txt 

Linux操作系统:

perl -lne 'print $_ if $_ !~ m/foo\s*bar/i && $_ =~ m/bar/i;' /tmp/xx.txt 

用含有xx.txt:

foo is bar 
hello bar 
foobar 
foo  bar 
barbar 
bar foo 
barfoo 
foo foo 

在命令提示执行一行程序的结果是:

foo is bar 
hello bar 
barbar 
bar foo 
barfoo 
相关问题