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


114

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

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

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

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

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


4
@poly: Это было не «обвинение», а спокойный, нормальный вопрос, на который вполне можно принять «нет» в качестве ответа. @Joshua: Да, некоторые люди (не так уж мало) позволяют этому сайту делать за них домашнее задание. Но задавать домашние задания - неплохая вещь на SO, если они отмечены как таковые. Обычно стиль ответов меняется с «вот решение» на «вот некоторые вещи, о которых вы не задумывались», и это хорошо. Кто-то должен стараться поддерживать различие, в его случае это был я, а где-то «другие люди» делают то же самое. Вот и все.
Tomalak

13
Надеюсь никогда не увидеть вопрос вроде «Это немного похоже на вопрос на рабочем месте. Не так ли?» и тогда люди будут спорить, делает ли переполнение стека чью-то работу.
Марсио

@Joshua +1 в отношении принятого вами решения с регулярным выражением, не могли бы вы рассказать мне, как я могу заменить совпадения (дубликаты) одним элементом пары (например, not that that is related-> not that is related)? Заранее спасибо
Antoine

@Joshua Я думаю, что нашел решение: я должен заменить на \1!
Антуан

2
@DavidLeal Как насчет \b(\w+)\s+(\1\s*)+\b?
ytu 05

Ответы:


141

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

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

Вот \bграница слова и \1ссылка на зафиксированное совпадение первой группы.


1
Удиви меня; можно \0тоже сделать ? (Где \0находится все регулярное выражение, до текущей точки ИЛИ где \0относится ко всему регулярному выражению)
Пиндатджух

@Pindatjuh: Нет, я так не думаю, потому что этот вспомогательный матч также будет частью всего матча.
Гамбо

По крайней мере, работает с механизмом регулярных выражений, используемым в диалоговом окне поиска / замены Eclipse.
Chaos_99

3
Просто предупреждение, это не касается слов с апострофами или (как упоминает Ноэль) хайпов. Решение Майка работает лучше в этих случаях

3
Более того, он не поймает троек (или больше), если один из дубликатов / трех экземпляров находится в конце строки,
Нико

20

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

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

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


Отлично, работает с апострофами / дефисами и т. Д. тоже - спасибо!

Что вы помещаете в область замены, чтобы использовать сгруппированное слово для ссылки "проблема1"? Пробовал, <strong>\0</strong>но не работает.
uptownhr

2
Он не будет ловить троек (или больше), если один из дубликатов / тройных копий находится в конце строки
Нико

@uptownhr Вы хотите использовать $1 <strong>$2</strong>. Но также используйте другое регулярное выражение /\b(\S+) (\1)\b/gi. Вот ссылка: callumacrae.github.io/regex-tuesday/…
dsalaj

и если я хочу найти все последовательные слова из определенного тега, например, как <p class="bebe">bla bla</p>я могу интегрировать эту формулу регулярного выражения?
Just Me

7

Попробуйте это с 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();
    }

5

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

(\b\w+\b)\W+\1

Вам нужно что-то, чтобы сопоставить символы между двумя словами, например \W+. \bне будет этого делать, потому что не потребляет никаких символов.
Алан Мур,

Это потенциально может привести к ложноположительному совпадению в таких случаях, как ... the these problems.... Это решение не так надежно, как общая структура паттерна Гамбо, который в достаточной мере реализует границы слов.
mickmackusa 01

и если я хочу найти все последовательные слова из определенного тега, например, как <p class="bebe">bla bla</p>я могу интегрировать эту формулу регулярного выражения?
Just Me

5

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

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 goodbye GooDbYe

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

Объяснение:

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

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

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

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

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

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

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

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


4

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

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

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

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


Этот ответ вводит в заблуждение. Он не ищет дубликаты, он ищет подстроки с 3 или более вхождениями. Это также не очень надежно из- \s*за группы захвата. См. Эту демонстрацию: regex101.com/r/JtCdd6/1
mickmackusa 01

Кроме того, в крайних случаях (низкочастотный текст) могут возникнуть ложноположительные совпадения. Например , I said "oioioi" that's some wicked mistressship!на oioioiиsss
mickmackusa

3

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


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

3

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

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

и если я хочу найти все последовательные слова из определенного тега, например, как <p class="bebe">bla bla</p>я могу интегрировать эту формулу регулярного выражения?
Just Me

Я считаю, что это потребует синтаксического анализа HTML. Для любого заданного тега, который вы хотите найти, найдите все вхождения тегов внутри HTML и запустите это регулярное выражение по одному для каждого из них. Или, если вас не заботит, где в HTML происходит повторение, объедините все атрибуты текста тега и запустите регулярное выражение для объединенной строки
synaptikon

Я нахожу ответ<p class="bebe">.*?\b\s+(\w+)\b\K\s+\1\s+\b(?=.*?<\/p>)
Just Me

3

Регулярное выражение для удаления 2+ повторяющихся слов (последовательные / непоследовательные слова)

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

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

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

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


1
Непоследовательный - плохая идея: "the cat sat on the mat"->" cat sat on the mat"
Walf

@Walf Верно. Тем не менее, есть сценарии, в которых это предусмотрено. (например: пока
собирает

Почему вы снова сломали свое регулярное выражение после того, как я его исправил ? Вы думали, я изменил его намерения? Даже в приведенном вами примере нет ошибки.
Walf

Да, это была ошибка, копия вставила неправильный материал. На самом деле он предназначен для копирования того, что было в моем примере. во всяком случае, теперь это работает! так что все хорошо! Спасибо!
Никет Патхак

2

Пример на 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]. Если вы не возражаете против этого ограничения, принятый ответ в порядке.


2

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

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

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

В частности:

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

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


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

1

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

/(^|\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

У меня проблемы с переписыванием этого на PHP, очень важно, чтобы я получил одну копию совпадающего дубликата, заменяя каждое вхождение дубликатов / троек и т. Д. Пока у меня есть: preg_replace ('/ (^ | \ s +) (\ S +) ( ($ | \ s +) \ 2) + / im ',' $ 0 ', $ string);
AdamJones

Это лучший ответ. Я просто изменил это, добавив \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Уведомлением string stringing. Он совпадает с вашим ответом. Спасибо.
Ste

-1

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

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

Использование модификатора шаблона без учета регистра не имеет смысла для вашего шаблона. У флага нет диапазонов букв.
mickmackusa 01

Это фактически дубликат принятого ответа и не добавляет ценности странице. Пожалуйста, подумайте об удалении этого ответа, чтобы уменьшить раздувание страницы.
mickmackusa 01
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.