4

Как составить регулярное выражение на поиск слов(а) в тексте при условии, что данное слово появляется более n-раз.

Пример.

Ищем слово 'world', которое встречается ровно 3 и более раза

  1. Hello my world
  2. Hello my world, hello my world, hello my world

Регулярка не должна находить соответствие в первом тексте, но во втором найдет все 3 и более слова.

lolokot
  • 320
  • php? javascript? – cyadvert Oct 20 '15 at 14:29
  • А ведь минусующие возможно не поняли вопроса. Нужно найти только повторяющиеся слова, а не все. – Visman Oct 20 '15 at 14:36
  • Поиском пользовался и ничего не добился. – lolokot Oct 20 '15 at 14:37
  • Нужно именно повторы найти, мне не надо все найти, а только то, что повторяется и определенное кол-во раз. Язык PHP,Java, JS. Мне желательно чистый RegEx без привязки к конкретному языку программирования – lolokot Oct 20 '15 at 14:39
  • @lolokot, что-то мне подсказывает, что проще и правильнее отобрать все вхождения подстроки и оценить их количество в программном коде. – Dmitriy Simushev Oct 20 '15 at 15:04
  • могу на Java предложить вариант такой регулярки, если интересно – redL1ne Oct 20 '15 at 15:05
  • 2
    Кажется вот то, что Вам нужно: http://stackoverflow.com/questions/16333681/regex-repeated-words-on-the-same-line – cyadvert Oct 20 '15 at 15:07
  • @Александр если Вам не сложно, то предоставьте данный код – lolokot Oct 20 '15 at 15:10
  • @DmitriySimushev это да, но проблема в том, что вероятность внедрения кода меньше чем регулярки – lolokot Oct 20 '15 at 15:11
  • Считаю, что решить задачу чистой регуляркой невозможно. Код на языке применения все равно нужен для обработки результата. – Visman Oct 20 '15 at 15:57
  • @Visman чистой регуляркой уже сделали, осталось понять как работает. Пример у DmitriySimushev – lolokot Oct 20 '15 at 16:02
  • @lolokot, вы ошибаетесь. Разве та регулярка вам вернула все вхождения слова? – Visman Oct 20 '15 at 16:07
  • @Visman как я понимаю, то не все. Она ищет все вхождения, которые не включены в лимит,т.е. задаю {1,} он найдет все слова кроме 1 и так далее. – lolokot Oct 20 '15 at 16:17
  • @lolokot, эта регулярка не выполняет того, что вы сформулировали в своем вопросе. Пока я остаюсь при своем мнении: чистой регуляркой нельзя вернуть все вхождения слова в предложение, если оно встречается там более n раз. – Visman Oct 20 '15 at 16:22

4 Answers4

1

UPD

Я бы просто пользовался обратными ссылками:

^.*(world)(.*(\1)){2}.*$
                   ^ n-1 раз повторений

Пример: https://regex101.com/r/zK2hG2/3

  • Угу. А если ему надо найти вхождение слова более 2 раз, например, а вхождений слова в предложение 5? – Visman Oct 20 '15 at 15:25
  • Согласен, поспешил. Обновил. – streetturtle Oct 20 '15 at 15:30
  • Да проблема не в этом, а вот в чем -> все 3 и более слова То есть по вопросу получается, что регулярка должна вернуть столько групп сколько искомых слов есть в предложении, если количество вхождений слова больше n. P.S. Думаю чистой регуляркой это не решить. – Visman Oct 20 '15 at 15:35
  • Либо текст вопроса сформирован не верно :) – Visman Oct 20 '15 at 15:36
  • Зачем ставить начало и конец строки, если рядом .*? – Qwertiy Oct 20 '15 at 15:41
  • Данная регулярка всю строку ищет) А нужно лишь конкретное кол-во слов в строке. – lolokot Oct 20 '15 at 15:50
  • Задача - найти слово: "Ищем слово 'world'..." то есть надо найти слово. Искомое слово будет в первой группе. Про ^ и $ можно и не ставить, ошибся. @Visman @Qwertiy @lolokot – streetturtle Oct 20 '15 at 15:52
  • @streetturtle но находит все строку судя по ссылке из вашего примера – lolokot Oct 20 '15 at 15:53
1

Можно попробовать вот такой вариант (на основе на основе этого ответа):

/(\b\w+\b)(?=(?:.*?\b\1\b){2,})/ig

Пример: https://regex101.com/r/cS2sH3/1

Сразу обращаю внимание, что если вхождений больше трех, то слово будет выбрано несколько раз (количество вхождений минус 2).

Несколько пояснений о том, как работает это регулярное выражение:

  1. (\b\w+\b) маска захватывает "слово". При этом, символы \b обозначают границу слова и не захватываются маской.
  2. \1 используется для ссылки на найденную последовательность символов.
  3. .*?\b\1\b следует читать как "ранее найденное слово, которому предшествует один или более произвольных символов".
  4. (?: ... ){2,} определяется группа символов, которая повоторяется 2 или более раз. При этом используется незахватывающая маска (?:)
  5. Группа abc(?=def) проверяет, следует ли указанная группа символов за def за символами abc, не сдвигая при этом текущую позицию в строке.

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

Dmitriy Simushev
  • 17,999
  • 5
  • 49
  • 85
  • Если использовать программный код, то данный вопрос не появился тут. Дело в том, что данная регулярка подставляет как шаблон поиск в программу. Хотя можно ее переписать, но это займет некоторое время. Я не много не понимаю как работает Ваша регулярка. Можете по шагам разъяснить? – lolokot Oct 20 '15 at 15:49
  • @lolokot, дополнил ответ – Dmitriy Simushev Oct 20 '15 at 16:33
1
console.log([
"Hello my world",
"Hello my world, hello my world, hello my world",
"Hell hello he",
"123 1234 2345 3456 666 999 000 123",
"123 1234 2345 3456 123 666 999 123 000 123",].map(function(s) {
  var match = s.match(/\b(\w+)\b(?=(.*?\b\1\b){2})/gi);
  return match ? match.join(" ") : "";
}).join("\n"))

Вывод:

Hello my world


123 123

Чтобы слово находилось только один раз:

console.log([
"Hello my world",
"Hello my world, hello my world, hello my world",
"Hell hello he",
"123 1234 2345 3456 666 999 000 123",
"123 1234 2345 3456 123 666 999 000 123 123",].map(function(s) {
  var match = s.match(/\b(\w+)\b(?=(((?!\b\1\b).)*?\b\1\b){2}((?!\b\1\b).)*$)/gi);
  return match ? match.join(" ") : "";
}).join("\n"))

Вывод:

Hello my world


123
Qwertiy
  • 123,725
  • А чем ваша регулярка принципиально отличается от той, что у меня в ответе? ;) – Dmitriy Simushev Oct 20 '15 at 15:44
  • @DmitriySimushev 1. Я твой ответ не видел - у нас всего 2 минуты разница. 2. У тебя "или более" лишнее в "2 или более". 3. Сейчас исправлю, чтобы слово только один раз находилось. – Qwertiy Oct 20 '15 at 15:48
  • @DmitriySimushev, дополнил. – Qwertiy Oct 20 '15 at 15:51
  • 2 минуты это существенно ;) А если серьезно, то в вопросе нет указания на язык программирования. Более того, автор в комментариях указывает на необходимость решения без программного кода, а раз так, то ваш ответ по-сути идентичен моему. – Dmitriy Simushev Oct 20 '15 at 16:23
  • @DmitriySimushev, но тестить регулярку как-то надо было. В любом случае, с того момента, как я добавил ещё одну регулярку, находящую каждое слово ровно один раз, ответ уж точно стал не идентичен. – Qwertiy Oct 20 '15 at 16:26
0

По примеру, ищем world в строке Hello my world, hello my world, hello my world.

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

private final string REGEX = .+(world)+.{3,}

Объяснение:
.+ предполагает, что перед словом world могут быть любые символы либо другие слова.
+. предполагает, что после слова world так же могут быть другие символы или слова.
{3,} означает последовательность минимум из 3-х символов X, а X = world

P.S.: Если что-то не так, поправьте меня.

redL1ne
  • 2,190