Как найти слово, которому НЕ предшествует другое конкретное слово? - PullRequest
7 голосов
/ 02 декабря 2009

Какое регулярное выражение я могу использовать, чтобы найти все строки bar, перед которыми не стоит строка foo? Наличие пробела между ними также является незаконным.

Таким образом, регулярное выражение должно соответствовать следующим строкам

foo is bar
hello bar

Но не эти

foobar
foo     bar

Я пытался использовать следующее

(?!<foo)bar

и он выполняет работу по устранению foobar, но мне нужно позаботиться о пробелах и, конечно,

(?!<foo)\s*bar

соответствует всем строкам.

Спасибо!

Ответы [ 5 ]

4 голосов
/ 02 декабря 2009

Лучше использовать другие возможности языка программирования, чем искать шаблон для регулярных выражений.

Вы ищете строки, для которых $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
2 голосов
/ 02 декабря 2009

Учитывая несколько тестовых случаев

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 голосов
/ 08 мая 2013

Извлечение информации из предыдущих ответов, перенос в однострочную строку perl и создание регулярных выражений без учета регистра.

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

С 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
0 голосов
/ 02 декабря 2009

PHP:

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

Perl:

$string !~ /foo\s*bar/ && $string =~ /bar/
0 голосов
/ 02 декабря 2009
  (?!<foo)\s*bar

Это будет соответствовать пробелу

...