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


114

Я новачок із звичайним виразом, і я не можу зовсім зрозуміти, як написати єдиний регулярний вираз, який би "відповідав" будь-яким повторюваним послідовним словам, наприклад:

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

Не те, що пов'язано.

Чому ти смієшся? Чи мої регулярні вирази ЧОГО погані ??

Чи є один регулярний вираз, який буде відповідати ВСІМ жирним рядкам вище?


4
@poly: Це було не "звинувачення", а спокійне, нормальне запитання, яке ідеально може прийняти "ні" як відповідь. @ Джошуа: Так, деякі люди (не надто мало) дозволяють цьому сайту робити домашнє завдання за них. Але задавати питання домашнього завдання - це не погано, якщо це робиться на ПО, коли вони позначені як такі. Зазвичай стиль відповідей змінюється від "ось рішення" на "ось деякі речі, про які ти не думав", і це добре. Хтось повинен намагатися і не відставати, в його випадку це був я, а в інших місцях «інші люди» роблять те саме. Це все.
Томалак

13
Сподіваюся, що ніколи не побачите запитання на кшталт "Це звучить трохи як питання на робочому місці. Це?" і тоді люди будуть сперечатися, якщо переповнення стека виконує чиюсь роботу.
marcio

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

@Joshua Я думаю, що знайшов рішення: мене слід замінити на \1!
Антуан

2
@DavidLeal Як щодо \b(\w+)\s+(\1\s*)+\b?
ytu

Відповіді:


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-tu Tuesday/challenge1.html


Чудово, працює з апострофами / дефісами / тощо. теж - спасибі!

для посилання task1, що ви розміщуєте в області заміни, щоб використовувати груповане слово? Спробував, <strong>\0</strong>але не працює.
uptownhr

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

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

і якщо я хочу знайти всі послідовні слова з певного тегу, наприклад, <p class="bebe">bla bla</p>як я можу інтегрувати цю формулу регулярного виразка?
Тільки я

7

Спробуйте це з нижче RE

  • \ b початок межі слова слова
  • \ W + будь-який символ слова
  • \ Одне і те ж слово вже збігається
  • \ 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

і якщо я хочу знайти всі послідовні слова з певного тегу, наприклад, <p class="bebe">bla bla</p>як я можу інтегрувати цю формулу регулярного виразка?
Тільки я

4

Це регулярний вираз, який я використовую для видалення повторюваних фраз у своєму боті, що посмикується:

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

(\S+\s*) шукає будь-який рядок символів, який не є пробілом, а йде пробіл.

\1{2,}то шукає більше двох екземплярів цієї фрази в рядку. Якщо є 3 фрази, які однакові, вони збігаються.


Ця відповідь вводить в оману. Він не полює на дублікати, він полює на підрядки з 3 і більше входженнями. Він також не дуже надійний через \s*групу захоплення. Дивіться цю демонстрацію: regex101.com/r/JtCdd6/1
mickmackusa

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

4

Наведений нижче вираз повинен правильно працювати, щоб знайти будь-яку кількість послідовних слів. Відповідність може бути нечутливою до регістру.

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): повинен містити перше слово узгодженого шаблону у наведеному вище випадку Goodbye

Метод заміни повинен замінити всі послідовні відповідні слова першим екземпляром слова.


3

Ні. Це неправильна граматика. Можливо, ви можете використовувати регулярні вирази, що залежать від двигуна / мови, але не існує універсального регулярного виразу, який може це зробити.


12
Я маю на увазі правильність у строгому сенсі, але я вважаю, що вже не існує механізму регулярного вираження, який би не підтримував групування та зворотні посилання.
Томалак

3

Ось один, який ловить кілька слів кілька разів:

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

і якщо я хочу знайти всі послідовні слова з певного тегу, наприклад, <p class="bebe">bla bla</p>як я можу інтегрувати цю формулу регулярного виразка?
Тільки я

Я вважаю, що для цього знадобиться розбір HTML. Для будь-якого тегу, який ви хочете шукати, знайдіть усі події тегів всередині HTML і запустіть цей регулярний вираз по одному на кожному. Або якщо вам не байдуже, де в HTML відбувається повторення, об'єднайте всі атрибути тексту тегів і запустіть регулярний вираз на об'єднаному рядку
synaptikon

Я знаходжу собі відповідь<p class="bebe">.*?\b\s+(\w+)\b\K\s+\1\s+\b(?=.*?<\/p>)
Just Me

3

Regex to Strip 2+ дублюючих слів (послідовні / непослідовні слова)

Спробуйте цей регулярний вираз, який може вловлювати 2 або більше дублікатів слів і залишати після себе лише одне слово. І повторювані слова навіть не повинні бути послідовними .

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

Тут \bвикористовується для Word Boundary, ?=використовується для позитивного пошуку та \1використовується для зворотного посилання.

Приклад Джерело


1
"the cat sat on the mat"" cat sat on the mat"
Непослідовність

@Walf True. Тим не менш, є сценарії, де це призначено. (наприклад: під час
скреблінгу

Чому ти знову зламав регекс після того, як я його виправив ? Ви думали, що я змінив її намір? Навіть приклад, який ви зв'язали, не має помилки.
Вальф

Так, це була помилка, копія вставила неправильні речі. Мав намір скопіювати фактично з мого прикладу. все одно, це зараз працює! так що все добре! Дякую!
Нікет Патхак

2

Приклад у Javascript: Хороші частини можна адаптувати для цього:

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

1

Цей вираз (натхненний Майком, вище), схоже, охоплює всі дублікати, потрійні копії тощо, включаючи ті, що знаходяться в кінці рядка, чого більшість інших не робить:

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

Я знаю, що питання, яке задається, відповідати дублікатам , але у трьох примірниках є лише два дублікати поруч :)

По-перше, я (^|\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

Це фактично дублікат прийнятої відповіді і не додає ніякої цінності сторінці. Будь ласка, видаліть цю відповідь, щоб зменшити кількість розсипань сторінки.
mickmackusa
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.