2012-01-06 2 views
7

Корпус:регулярное выражение - совпадение слов только один раз в строке

  1. ehello до свидания hellot привет до свидания
  2. ehello до свидания привет привет до свидания

Я хочу, чтобы соответствовать линии 1 (имеет только «привет 'один раз!) НЕ хочу соответствовать строке 2 (содержит «привет» более одного раза)

Пробовал использовать негативный взгляд вперед, чтобы посмотреть, а что нет ... без каких-либо реальных succ ESS ..

ответ

4

Простой вариант это (используя флаг многострочного и не дот-все):

^(?!.*\bhello\b.*\bhello\b).*\bhello\b.*$ 

Во-первых, проверить вас не иметь «привет» в два раза, а затем проверить вас по крайней мере один раз.
Есть другие способы проверить одно и то же, но я думаю, что это довольно просто.

Конечно, вы можете просто матч за \bhello\b и подсчитать количество совпадений ...

+0

Почему бы просто не найти его один раз и проверить, что он не существует снова после этого? Кажется, это немного менее повторяется. – Wiseguy

+1

@Wiseguy - паттен, как '^. * Hello (?!. * Hello)' не будет работать, потому что он всегда будет соответствовать последнему «привет» строки. Вам нужно что-то вроде '^ (? :(?! hello).) * Hello (?!. * Hello)', что не намного элегантнее. Возможно, я пропустил что-то простое, хотя ... – Kobi

+0

@Wiseguy - no. Двигатель регулярных выражений пытается совместить, а не с отказом. Он может совпадать, так и будет. – Kobi

1

Поскольку вы беспокоитесь только о словах (то есть маркеры, разделенных пробелами), вы можете просто разделить на пространствах и посмотреть как часто появляется "hello". Так как вы не упомянул язык, вот реализация в Perl:

use strict; 
use warnings; 

my $a1="ehello goodbye hellot hello goodbye"; 
my $a2="ehello goodbye hello hello goodbye"; 

my @arr1=split(/\s+/,$a1); 
my @arr2=split(/\s+/,$a2); 

#grab the number of times that "hello" appears 

my $num_hello1=scalar(grep{$_ eq "hello"}@arr1); 
my $num_hello2=scalar(grep{$_ eq "hello"}@arr2); 

print "$num_hello1, $num_hello2\n"; 

Выход

1, 2 
2

Родовое регулярное выражение будет:

^(?:\b(\w+)\b\W*(?!.*?\b\1\b))*\z 

Altho это может быть чище чтобы инвертировать результаты этого матча:

\b(\w+)\b(?=.*?\b\1\b) 

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

+0

Doh, я неправильно понял вопрос, подумал, что «привет» может быть любым словом, и цель регулярного выражения состояла в том, чтобы убедиться, что слово не повторяется. Оставьте ответ в случае, если это кому-то интересно. – Qtax