Как выделить последовательные повторяющиеся слова с помощью регулярного выражения Perl? - PullRequest
6 голосов
/ 24 марта 2010

Мне нужно регулярное выражение Perl, которое будет соответствовать дублированным словам в строке.

С учетом следующего ввода:

$str = "Thus joyful Troy Troy maintained the the watch of night..."

Я хотел бы следующий вывод:

Thus joyful [Troy Troy] maintained [the the] watch of night...

Ответы [ 4 ]

12 голосов
/ 24 марта 2010

Это похоже на одно из Learning Perl упражнений. Хитрость заключается в том, чтобы перехватить все повторяющиеся слова, поэтому вам необходим квантификатор «один или несколько» при дублировании:

 $str = 'This is Goethe the the the their sentence';

 $str =~ s/\b((\w+)(?:\s+\2\b)+)/[\1]/g;

Функции, которые я собираюсь использовать, описаны либо в perlre , когда они применяются к шаблону, либо в perlop , когда они влияют на работу оператора подстановки.

Если вам нравится флаг /x для добавления незначительных пробелов и комментариев:

 $str =~ s/
      \b
      (
         (\w+)
         (?:
          \s+
          \2
          \b
         )+
      )
     /[\1]/xg;

Мне это не нравится \2, хотя, потому что я ненавижу считать относительные позиции. Я могу использовать относительные обратные ссылки в Perl 5.10. \g{-1} относится к непосредственно предшествующей группе захвата:

 use 5.010;
 $str =~ s/
      \b
      (
         (\w+)
         (?:
          \s+
          \g{-1}
          \b
         )+
      )
     /[\1]/xg;

Счет не так уж и велик, поэтому я могу использовать помеченные спички:

 use 5.010;
 $str =~ s/
      \b
      (
         (?<word>\w+)
         (?:
          \s+
          \k<word>
          \b
         )+
      )
     /[\1]/xg;

Я могу пометить первый захват ($1) и получить доступ к его значению через %+ позже:

 use 5.010;
 $str =~ s/
      \b
      (?<dups>
         (?<word>\w+)
         (?:
          \s+
          \k<word>
          \b
         )+
      )
     /[$+{dups}]/xg;

Мне действительно не нужен этот первый снимок, потому что он просто для того, чтобы ссылаться на все, что соответствует. К сожалению, похоже, что ${^MATCH} не установлено достаточно рано, чтобы я мог использовать его на стороне замены. Я думаю, что это ошибка. Это должно работать, но не работает:

 $str =~ s/
      \b
         (?<word>\w+)
         (?:
          \s+
          \k<word>
          \b
         )+
     /[${^MATCH}]/pgx;   # DOESN'T WORK

Я проверяю это на blead, но это займет немного времени, чтобы скомпилировать на моей крошечной машине.

10 голосов
/ 24 марта 2010

Это работает:

$str =~ s/\b((\w+)\s+\2)\b/[\1]/g;
2 голосов
/ 24 марта 2010

Вы можете попробовать:

$str = "Thus joyful Troy Troy maintained the the watch of night...";
$str =~s{\b(\w+)\s+\1\b}{[$1 $1]}g;
print "$str"; # prints Thus joyful [Troy Troy] maintained [the the] watch of night...

Используется регулярное выражение: \b(\w+)\s+\1\b

Пояснение:

  • \b: слово бондарий
  • \w+: слово
  • (): запомнить упомянутое слово
  • \s+: пробел
  • \1: запоминаемое слово

Эффективно находит два полных слова, разделенных пробелами и местами [ ] вокруг них.

EDIT:

Если вы хотите сохранить количество пробелов между словами, которые вы можете использовать:

$str =~s{\b(\w+)(\s+)\1\b}{[$1$2$1]}g;
0 голосов
/ 01 декабря 2016

Попробуйте следующее:

$str =~ s/\b(\S+)\b(\s+\1\b)+/[\1]/g;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...