How to find a word NOT preceded by another specific word?

亡梦爱人 提交于 2019-12-08 20:06:40

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!