可以使用哪个正则表达式来查找所有字符串bar
前面没有字符串foo
?两者之间有空白也是非法的。如何找到一个单词之前没有另一个特定的单词?
所以,正则表达式应该采用以下
(?!<foo)bar
符合下列字符串
foo is bar
hello bar
但不是这些
foobar
foo bar
我试着和它得到所做的工作消除foobar
,但我需要照顾的空白,当然
(?!<foo)\s*bar
匹配所有字符串。
谢谢!
可以使用哪个正则表达式来查找所有字符串bar
前面没有字符串foo
?两者之间有空白也是非法的。如何找到一个单词之前没有另一个特定的单词?
所以,正则表达式应该采用以下
(?!<foo)bar
符合下列字符串
foo is bar
hello bar
但不是这些
foobar
foo bar
我试着和它得到所做的工作消除foobar
,但我需要照顾的空白,当然
(?!<foo)\s*bar
匹配所有字符串。
谢谢!
(?!<foo)\s*bar
这将匹配空白
呃没有。首先,它是'(?<!..)',其次,'\ s *'需要在lookbehind内部,否则它总是匹配,除非'foo'和'bar'之间没有空格。马克·拜尔斯说得对。 – 2009-12-02 21:43:45
确定我所知道的是JA编辑我的答案,我感到有福。 – Hogan 2009-12-03 16:28:40
PHP:
!preg_match(/foo\s*bar/,$string) && preg_match(/bar/,$string)
的Perl:
$string !~ /foo\s*bar/ && $string =~ /bar/
正如原始问题中提到的,这不起作用。 – Sleepster 2009-12-02 20:49:54
嗯,是的,因为所有的字符串在技术上都可以被发现在非酒吧串之前... – 2009-12-02 20:56:45
你真正需要的是做一个负面的正则表达式。 $ string!〜/ foo \ s * bar /。用php和perl版本更新。 – 2009-12-02 21:02:30
鉴于一些测试用例
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";
}
令人印象深刻的是,你得到了这个工作。最有可能的“富”和“酒吧”只是更长的字符串的占位符。看起来你的正则表达式对于任何真实世界的例子都会变得非常长。尽管为不同的方法+1。 – 2009-12-02 23:28:17
谢谢,可悲的消息是字面模式是最好的情况。我想知道这种方法的局限性是什么。对于这样的任务来说,有一个正则表达式开关可以补充每个NFA状态的接受状态。 – 2009-12-03 19:54:26
更好地使用编程语言的其他工具,而不是看看太正确的正则表达式模式。
您在查找$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
即使字符串不包含“酒吧”,这不会匹配吗? – 2009-12-02 21:26:02
@Mark Byers:谢谢你指出我的疏忽。固定。 – 2009-12-02 21:51:22
'酒吧foobar'也使一个有趣的测试案例。虽然我不确定预期的输出是什么。 – 2009-12-02 22:30:15
以从早期的答案信息,包装作为一个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
“匹配所有字符串”。 - 迂回模式:(?!
2009-12-02 20:54:35
您说得对,谢谢指出! 我结束了使用以下内容: preg_match('/(foo)?\ s * bar /',haystack,matches); 这将找到酒吧(无论前面是否有foo),然后对匹配[]进行快速检查将确定foo是否存在。 – Sleepster 2009-12-03 00:34:25
您正在寻找的东西具体称为**零宽度负面后顾断言**。 Perl显然不支持可变宽度后视(正面或负面),所以像\ s *之类的东西在其中一个将不起作用。尝试使用多个匹配运算符。 – fennec 2009-12-30 05:25:54