Регулярное выражение для повторяющихся слов

Я новичок в регулярных выражениях и не могу понять, как написать одно регулярное выражение, которое соответствовало бы любым повторяющимся последовательным словам, например:

Париж весной.

Не это связано.

Над чем ты смеешься? Неужели мои регулярные выражения ТАК плохи ??

Есть ли одно регулярное выражение, которое будет соответствовать ВСЕМ строкам, выделенным жирным шрифтом выше?


person Joshua    schedule 12.05.2010    source источник
comment
@poly: Это было не обвинение, а спокойный, нормальный вопрос, на который вполне можно принять отрицание как ответ. @Joshua: Да, некоторые люди (не так уж мало) позволяют этому сайту делать за них домашнюю работу. Но задавать домашние задания - неплохая вещь на SO, когда они отмечены как таковые. Обычно стиль ответов меняется, поэтому здесь есть некоторые вещи, о которых вы не задумывались, и это хорошо. Кто-то должен стараться поддерживать различие, в его случае это был я, а где-то другие люди делают то же самое. Это все.   -  person Tomalak    schedule 13.05.2010
comment
Надеюсь никогда не увидеть такой вопрос. Это немного похоже на вопрос на рабочем месте. Это? и тогда люди будут спорить, если переполнение стека выполняет чью-то работу.   -  person marcio    schedule 11.12.2014
comment
@Joshua +1 в отношении принятого вами решения с регулярным выражением, не могли бы вы рассказать мне, как я могу заменить совпадения (дубликаты) одним элементом пары (например, not that that is related - ›not that is related)? заранее спасибо   -  person Antoine    schedule 20.04.2016
comment
@Joshua Я думаю, что нашел решение: я должен заменить его на \1!   -  person Antoine    schedule 20.04.2016
comment
Это решение обрабатывает последовательные повторяющиеся слова, как насчет более общей ситуации: когда количество повторяющихся слов больше 2 ?, например: Не то, чтобы это связано.   -  person David Leal    schedule 15.02.2017
comment
@DavidLeal Как насчет \b(\w+)\s+(\1\s*)+\b?   -  person ytu    schedule 05.06.2018
comment
Этот ответ касается как последовательных, так и непоследовательных повторяющихся слов.   -  person Wiktor Stribiżew    schedule 11.03.2020
comment
осторожно: не то, чтобы это связано. Но ... может быть правильная грамматика. Или хотя бы использование. Но это в других контекстах совершенно правильно (... чтобы эта нация могла существовать ...)   -  person Nils Sens    schedule 12.07.2020


Ответы (13)


Попробуйте это регулярное выражение:

\b(\w+)\s+\1\b

Здесь \b - это граница слова, а \1 ссылается на зафиксированное совпадение первой группы.

person Gumbo    schedule 12.05.2010
comment
Удиви меня; можно ли тоже сделать \0? (Где \0 - это все регулярное выражение до текущей точки ИЛИ, где \0 относится ко всему регулярному выражению) - person Pindatjuh; 13.05.2010
comment
@Pindatjuh: Нет, я так не думаю, потому что этот дополнительный матч также будет частью всего матча. - person Gumbo; 13.05.2010
comment
По крайней мере, работает с механизмом регулярных выражений, используемым в диалоговом окне поиска / замены Eclipse. - person Chaos_99; 24.05.2013
comment
Это будет рассматривать дефисы и т. Д. Как обозначение границы слова, например the the-foo bar. @ Ответ Даниэля немного более правильный. - person Noel Abrahams; 15.04.2015
comment
Просто предупреждение, это не касается слов с апострофами или (как упоминает Ноэль) хайпов. Решение Майка работает лучше в этих случаях - person ; 13.05.2015
comment
Более того, он не будет ловить трижды (или больше), а не когда один из дубликатов / трех экземпляров находится в конце строки - person Nico; 18.02.2016
comment
+1 красивое решение. Не могли бы вы сказать мне, как заменить совпадения (дубликаты) первым элементом пары (например, and and должен стать and)? - person Antoine; 20.04.2016
comment
Не знаю, что это не работает в Python, мне нравится регулярное выражение. Когда я пытаюсь вызвать функцию сопоставления, она всегда возвращает None - person Lucas Huang; 20.01.2018
comment
@LucasHuang Попробуй re.search. См. Раздел search () vs. match (). - person ytu; 05.06.2018
comment
и если я хочу найти все последовательные слова из определенного тега, например <p class="bebe">bla bla</p>, как я могу интегрировать эту формулу регулярного выражения? - person Just Me; 22.04.2019
comment
Не работает, если 2-е слово - последнее слово в строке. Регулярное выражение \b(\w+)\s+\1$ работает в этих случаях, но не работает, когда второе слово не находится в конце строки. Любые идеи? [edit] Нашел ответ: \b(\w+)\s+\1(?:\s|$) - person Mark Jeronimus; 04.08.2019

Я считаю, что это регулярное выражение обрабатывает больше ситуаций:

/(\b\S+\b)\s+\b\1\b/

Хороший выбор тестовых строк можно найти здесь: http://callumacrae.github.com/regex-tuesday/challenge1.html

person Mike Viens    schedule 06.09.2012
comment
Отлично, работает с апострофами / дефисами и т. Д. тоже - спасибо! - person ; 13.05.2015
comment
что вы помещаете в область замены, чтобы использовать сгруппированное слово для ссылки "проблема1"? Пробовал <strong>\0</strong>, но не работает. - person uptownhr; 08.02.2016
comment
Он не будет ловить трижды (или больше), не когда один из дубликатов / трех экземпляров находится в конце строки - person Nico; 18.02.2016
comment
@uptownhr Вы хотите использовать $1 <strong>$2</strong>. Но также используйте другое регулярное выражение /\b(\S+) (\1)\b/gi. Вот ссылка: callumacrae.github.io/regex-tuesday/ - person dsalaj; 09.08.2018
comment
и если я хочу найти все последовательные слова из определенного тега, например <p class="bebe">bla bla</p>, как я могу интегрировать эту формулу регулярного выражения? - person Just Me; 22.04.2019

Попробуйте это с RE ниже

  • \ b начало слова границы слова
  • \ W + любой символ слова
  • \ 1 такое же слово уже найдено
  • \ b конец слова
  • () * Повторение снова

    public static void main(String[] args) {
    
        String regex = "\\b(\\w+)(\\b\\W+\\b\\1\\b)*";//  "/* Write a RegEx matching repeated words here. */";
        Pattern p = Pattern.compile(regex, Pattern.CASE_INSENSITIVE/* Insert the correct Pattern flag here.*/);
    
        Scanner in = new Scanner(System.in);
    
        int numSentences = Integer.parseInt(in.nextLine());
    
        while (numSentences-- > 0) {
            String input = in.nextLine();
    
            Matcher m = p.matcher(input);
    
            // Check for subsequences of input that match the compiled pattern
            while (m.find()) {
                input = input.replaceAll(m.group(0),m.group(1));
            }
    
            // Prints the modified sentence.
            System.out.println(input);
        }
    
        in.close();
    }
    
person Faakhir    schedule 05.06.2017

Приведенное ниже выражение должно работать правильно, чтобы найти любое количество последовательных слов. Сопоставление может быть нечувствительным к регистру.

String regex = "\\b(\\w+)(\\s+\\1\\b)*";
Pattern p = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);

Matcher m = p.matcher(input);

// Check for subsequences of input that match the compiled pattern
while (m.find()) {
     input = input.replaceAll(m.group(0), m.group(1));
}

Пример ввода: Прощай, прощай, GooDbYe

Пример вывода: до свидания

Объяснение:

Выражение регулярного выражения:

\ b: начало границы слова

\ w +: любое количество символов слова

(\ s + \ 1 \ b) *: любое количество пробелов, за которым следует слово, которое соответствует предыдущему слову и заканчивается границей слова. Всё, завернутое в *, помогает найти более одного повтора.

Группировка:

m.group (0): должна содержать совпавшую группу в приведенном выше случае. До свидания, до свидания, GooDbYe.

m.group (1): Должен содержать первое слово совпадающего шаблона в приведенном выше случае. До свидания.

Метод Replace заменяет все последовательные совпадающие слова первым экземпляром слова.

person Akriti    schedule 11.03.2019

Regex to Strip 2+ duplicate words (consecutive/non-consecutive words)

Попробуйте это регулярное выражение, которое может поймать 2 или более повторяющихся слова и оставить только одно слово. И повторяющиеся слова не обязательно должны быть последовательными.

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

Здесь \b используется для границы слова, ?= используется для положительного просмотра вперед, а \1 используется для обратной ссылки.

Пример Источник

person Niket Pathak    schedule 05.07.2018
comment
Непоследовательные - плохая идея: "the cat sat on the mat" - ›" cat sat on the mat" - person Walf; 06.12.2018
comment
@Walf Верно. Тем не менее, есть сценарии, в которых это задумано. (например: при считывании данных) - person Niket Pathak; 06.12.2018
comment
Почему вы снова нарушили регулярное выражение после Я поправил? Вы думали, я изменил его намерения? Даже в приведенном вами примере нет ошибки. - person Walf; 06.12.2018
comment
Да, это была ошибка, копия вставила неправильный материал. На самом деле он предназначен для копирования того, что было в моем примере. во всяком случае, теперь это работает! так что все хорошо! Спасибо! - person Niket Pathak; 07.12.2018
comment
У меня был аналогичный вариант использования для удаления повторяющихся символов из строки в java, и ваше решение мне помогло. Спасибо. Если кто-то еще ищет код для удаления повторяющихся символов из String в java - s1.replaceAll ((.) (? =. *? \\ 1),) - person tanson; 11.06.2021

Широко используемая библиотека PCRE может справиться с такими ситуациями (однако вы не получите того же с POSIX-совместимыми механизмами регулярных выражений):

(\b\w+\b)\W+\1
person soulmerge    schedule 12.05.2010
comment
Вам нужно что-то, чтобы сопоставить символы между двумя словами, например \W+. \b этого не сделает, потому что не потребляет никаких символов. - person Alan Moore; 13.05.2010
comment
Это потенциально может привести к ложноположительному совпадению в таких случаях, как ... the these problems.... Это решение не так надежно, как общая структура паттерна Гамбо, который в достаточной степени реализует границы слов. - person mickmackusa; 01.02.2018
comment
и если я хочу найти все последовательные слова из определенного тега, например <p class="bebe">bla bla</p>, как я могу интегрировать эту формулу регулярного выражения? - person Just Me; 22.04.2019

Нет. Это неправильная грамматика. Вы можете использовать регулярные выражения для конкретного движка / языка, но не существует универсального регулярного выражения, которое могло бы это сделать.

person Ignacio Vazquez-Abrams    schedule 12.05.2010
comment
Хотя это и верно в строгом смысле слова, я считаю, что больше нет серьезного использования механизма регулярных выражений, который не поддерживает группировку и обратные ссылки. - person Tomalak; 13.05.2010

Это регулярное выражение, которое я использую для удаления повторяющихся фраз в моем Twitch-боте:

(\S+\s*)\1{2,}

(\S+\s*) ищет любую строку символов, не являющуюся пробелом, за которой следует пробел.

\1{2,} затем ищет более двух экземпляров этой фразы в строке для сопоставления. Если есть 3 одинаковых фразы, они совпадают.

person Neceros    schedule 18.07.2015
comment
Этот ответ вводит в заблуждение. Он не ищет дубликаты, он ищет подстроки с 3 или более вхождениями. Это также не очень надежно из-за \s* в группе захвата. См. Эту демонстрацию: regex101.com/r/JtCdd6/1 - person mickmackusa; 01.02.2018
comment
Более того, в крайних случаях (низкочастотный текст) могут возникнуть ложноположительные совпадения. Например. I said "oioioi" that's some wicked mistressship! на oioioi и sss - person mickmackusa; 01.02.2018

Вот тот, который несколько раз перехватывает несколько слов:

(\b\w+\b)(\s+\1)+
person synaptikon    schedule 24.03.2018
comment
и если я хочу найти все последовательные слова из определенного тега, например <p class="bebe">bla bla</p>, как я могу интегрировать эту формулу регулярного выражения? - person Just Me; 22.04.2019
comment
Я считаю, что это потребует синтаксического анализа HTML. Для любого заданного тега, который вы хотите найти, найдите все вхождения тегов внутри HTML и выполните это регулярное выражение одно за другим для каждого из них. Или, если вас не волнует, где в HTML происходит повторение, объедините все атрибуты текста тега и запустите регулярное выражение для объединенной строки - person synaptikon; 24.04.2019
comment
Я нахожу ответ <p class="bebe">.*?\b\s+(\w+)\b\K\s+\1\s+\b(?=.*?<\/p>) - person Just Me; 25.04.2019

Пример на Javascript: The Good Parts можно адаптировать для этого:

var doubled_words = /([A-Za-z\u00C0-\u1FFF\u2800-\uFFFD]+)\s+\1(?:\s|$)/gi;

\ b использует \ w для границ слова, где \ w эквивалентно [0-9A-Z_a-z]. Если вы не возражаете против этого ограничения, принятый ответ в порядке.

person Daniel    schedule 24.04.2013

Поскольку некоторые разработчики заходят на эту страницу в поисках решения, которое не только устраняет повторяющиеся последовательные подстроки без пробелов, но и трижды, я покажу адаптированный шаблон.

Шаблон: /(\b\S+)(?:\s+\1\b)+/ (Образец демонстрации)
Заменить: $1 (заменяет совпадение полной строки захватом группа 1)

Этот шаблон жадно сопоставляет «целую» подстроку без пробелов, а затем требует одну или несколько копий сопоставленной подстроки, которые могут быть разделены одним или несколькими пробельными символами (пробел, табуляция, новая строка и т. Д.).

Конкретно:

  • Символы \b (границы слова) жизненно важны для предотвращения совпадения частичных слов.
  • Вторая скобка - это группа без захвата, потому что эту подстроку переменной ширины не нужно захватывать - нужно только сопоставить / поглотить.
  • + (один или несколько квантификаторов) в группе без захвата более уместен, чем *, потому что * будет «мешать» механизму регулярных выражений захватывать и заменять вхождения синглтонов - это расточительный дизайн шаблона.

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

person mickmackusa    schedule 01.02.2018
comment
@AdamJones использует этот шаблон в своем проекте php. В ответе Нико есть ненужный синтаксис. - person mickmackusa; 01.02.2018

Это выражение (вдохновленное Майком, приведенным выше), кажется, улавливает все дубликаты, трижды и т. Д., Включая те, которые находятся в конце строки, чего нет у большинства других:

/(^|\s+)(\S+)(($|\s+)\2)+/g, "$1$2")

Я знаю, что вопрос задан для сопоставления только дубликатов, но три дубликата - это всего лишь 2 дубликата рядом друг с другом :)

Сначала я поставил (^|\s+), чтобы убедиться, что он начинается с полного слова, иначе «детский стейк» перейдет в «детский стейк» (буквы «s» будут соответствовать). Затем он сопоставляет все полные слова ((\b\S+\b)), за которыми следует конец строки ($) или количество пробелов (\s+), все повторяется более одного раза.

Я пробовал вот так, и все получилось:

var s = "here here here     here is ahi-ahi ahi-ahi ahi-ahi joe's joe's joe's joe's joe's the result result     result";
print( s.replace( /(\b\S+\b)(($|\s+)\1)+/g, "$1"))         
--> here is ahi-ahi joe's the result
person Nico    schedule 18.02.2016
comment
У меня проблемы с переписыванием этого на PHP, жизненно важно, чтобы я получил одну копию совпадающего дубликата, заменяя каждое вхождение дубликатов / троек и т.д. Пока у меня есть: preg_replace ('/ (^ | \ s +) (\ S +) ( ($ | \ s +) \ 2) + / im ',' $ 0 ', $ string); - person AdamJones; 28.02.2017
comment
Это лучший ответ. Я просто изменил это, добавив \b в конец следующим образом: /(^|\s+)(\S+)(($|\s+)\2)+\b/g, "$1$2") Это будет работать в таких ситуациях: the the string String string stringing the the along the the string станет the string stringing the along the string Notice string stringing. Он совпадает с вашим ответом. Спасибо. - person Ste; 18.08.2019

Используйте это в случае, если вы хотите проверять наличие повторяющихся слов без учета регистра.

(?i)\\b(\\w+)\\s+\\1\\b
person Neelam    schedule 16.08.2016
comment
Использование модификатора шаблона без учета регистра не имеет смысла для вашего шаблона. У флага нет буквенных диапазонов. - person mickmackusa; 01.02.2018
comment
По сути, это дубликат принятого ответа, который не добавляет ценности странице. Пожалуйста, подумайте об удалении этого ответа, чтобы уменьшить раздувание страницы. - person mickmackusa; 01.02.2018