2009-12-02 117 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 
相關問題