Регулярное выражение для последовательных повторяющихся биграмм
Мой вопрос является прямым продолжением этого более раннего вопроса об обнаружении последовательных слов (униграмм) в строке.
В предыдущем вопросе
Не то что связано
может быть обнаружено с помощью этого регулярного выражения: \b(\w+)\s+\1\b
Здесь я хочу обнаружить последовательные биграммы (пары слов):
синие и то и то очень яркие
В идеале я также хочу знать, как заменить обнаруженный шаблон (дубликат) одним элементом, чтобы в итоге получить:
синие и очень яркие
(для этого приложения, если это имеет значение, я использую gsub
в R)
2 ответа
Дело в том, что в некоторых случаях будут повторяющиеся подстроки, которые включают более короткие повторные подстроки. Таким образом, чтобы соответствовать более длинным, вы должны использовать
(\b.+\b)\1\b
(см. демонстрационный пример регулярных выражений), и для поиска более коротких подстрок я бы использовал ленивое сопоставление точек:
(\b.+?\b)\1\b
Смотрите это регулярное выражение. Строка замены будет \1
- обратная ссылка на захваченную часть, сначала сопоставленную с конструкцией группировки (...)
,
Вам нужно регулярное выражение PCRE, чтобы оно работало, поскольку есть задокументированные проблемы с соответствием границ нескольких слов с gsub
(так, добавьте perl=T
аргумент).
Режим POSIX 1003.2 для gsub и gregexpr не работает правильно с повторяющимися границами слов (например,
pattern = "\b"
). использованиеperl = TRUE
для таких совпадений (но это может не работать должным образом с входными данными, не относящимися к ASCII, поскольку значение слова зависит от системы).
Обратите внимание, что если ваши повторяющиеся подстроки могут занимать несколько строк, вы можете использовать регулярное выражение PCRE с модификатором DOTALL (?s)
в начале шаблона (так что .
может также соответствовать символу новой строки).
Итак, код R будет выглядеть
gsub("(?s)(\\b.+\\b)\\1\\b", "\\1", s, perl=T)
или же
gsub("(?s)(\\b.+?\\b)\\1\\b", "\\1", s, perl=T)
Смотрите демоверсию IDEONE:
text <- "are blue and then and then more and then and then more very bright"
gsub("(?s)(\\b.+?\\b)\\1\\b", "\\1", text, perl=T) ## shorter repeated substrings
## [1] "are blue and then more and then more very bright"
gsub("(?s)(\\b.+\\b)\\1\\b", "\\1", text, perl=T) ## longer repeated substrings
## [1] "are blue and then and then more very bright"
Попробуйте следующий RegEx:
(\b.+?\b)\1\b
RegEx захватывает границу слова, затем данные и затем границу слова. \1
будет ссылаться на то, что было захвачено, и выберите это снова. Затем он проверит на границу слова конец, чтобы предотвратить a and
а также z zoo
из выбранных
Что касается замены, используйте \1
, Это будет содержать данные из 1st
Capture Group (первая часть биграммы), и эта первая часть будет использоваться для замены всего этого.