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

Кейс:

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

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

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


person user1135229    schedule 06.01.2012    source источник


Ответы (3)


Вот простой вариант (используя многострочный флаг, а не многоточие):

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

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

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

person Kobi    schedule 06.01.2012
comment
Почему бы просто не найти его один раз и после этого снова не проверить, что его не существует? Кажется, что так повторяется меньше. - person Wiseguy; 07.01.2012
comment
@Wiseguy - шаблон типа ^.*hello(?!.*hello) не будет работать, потому что он всегда будет соответствовать последнему hello строки. Вам понадобится что-то вроде ^(?:(?!hello).)*hello(?!.*hello), что не намного элегантнее. Хотя, возможно, я упустил что-то простое... - person Kobi; 07.01.2012
comment
@Wiseguy - нет. Механизм регулярных выражений пытается сопоставить, а не ошибиться. Может совпадать, значит будет. - person Kobi; 07.01.2012
comment
Работает, просто, понятно. - person user1135229; 07.01.2012

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

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

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

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

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

person Qtax    schedule 06.01.2012
comment
Дох, я неправильно понял вопрос, подумал, что hello может быть любым словом, а цель регулярного выражения состояла в том, чтобы убедиться, что ни одно слово не повторяется. Оставлю ответ на случай, если это кого-то заинтересует. - person Qtax; 07.01.2012

Поскольку вас интересуют только слова (т. е. токены, разделенные пробелами), вы можете просто разделить на пробелы и посмотреть, как часто появляется "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
person Community    schedule 06.01.2012