问题
Which regular expression can I use to find all strings bar
are not preceded by string foo
? Having whitespace between the two is also illegal.
So the regex should match the following strings
foo is bar
hello bar
But not these
foobar
foo bar
I've tried using the following
(?!<foo)bar
and it gets the work done for eliminating foobar
, but I need to take care of the whitespace, and of course
(?!<foo)\s*bar
matches all the strings.
Thanks!
回答1:
Better to use other facilities of the programming language than to look too hard for a regex pattern.
You are looking for strings for which $s =~ /bar/ and not $s =~ /foo\s*bar/
is true.
The rest of the script below is just for testing.
#!/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";
}
}
Output:
E:\srv\unur> j Good: bar foo Good: hello bar Good: foo is bar Good: barbar Good: foo foo Good: foo bar Good: foobar
回答2:
Given a few test cases
my @match = (
"foo is bar",
"hello bar",
);
my @reject = (
"foobar",
"foo bar",
);
you could of course do by feeding the results of one pattern to another:
my @control = grep !/foo\s*bar/, grep /bar/ => @match, @reject;
We can also do it with one:
my $nofoo = qr/
( [^f] |
f (?! o) |
fo (?! o \s* bar)
)*
/x;
my $pattern = qr/^ $nofoo bar /x;
But don't take my word for it.
for (@match) {
print +(/$pattern/ ? "PASS" : "FAIL"), ": $_\n";
}
for (@reject) {
print +(/$pattern/ ? "FAIL" : "PASS"), ": $_\n";
}
回答3:
(?!<foo)\s*bar
This will match the whitespace
回答4:
php:
!preg_match(/foo\s*bar/,$string) && preg_match(/bar/,$string)
perl:
$string !~ /foo\s*bar/ && $string =~ /bar/
回答5:
Taking the information from earlier answers, wrapping as a perl one-liner, and making the regular expressions case-insensitive.
Windows:
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
With xx.txt containing:
foo is bar
hello bar
foobar
foo bar
barbar
bar foo
barfoo
foo foo
The result of executing the one-liner at a command prompt:
foo is bar
hello bar
barbar
bar foo
barfoo
来源:https://stackoverflow.com/questions/1835636/how-to-find-a-word-not-preceded-by-another-specific-word