Захватить n буквенных слов не считайте регулярное выражение апострофов
Я пытаюсь изучить regex in R более глубоко. Я дал себе то, что, по моему мнению, было легкой задачей, которую я не могу понять. Я хочу извлечь все 4 буквы. В этих четырех буквенных словах я хочу игнорировать (не считать) апострофы. Я могу сделать это без регулярного выражения, но хочу использовать регулярное выражение. Здесь MWE и то, что я пробовал:
text.var <- "This Jon dogs' 'bout there in Mike re'y word."
pattern <- "\\b[A-Za-z]{4}\\b(?!')"
pattern <- "\\b[A-Za-z]{4}\\b|\\b[A-Za-z']{5}\\b"
regmatches(text.var, gregexpr(pattern, text.var, perl = TRUE))
** Требуемый вывод: **
[[1]]
[1] "This" "Jon's" "dogs'" "'bout" "word"
Я думал, что второй шаблон будет работать, но он захватывает слова, содержащие 5 символов.
Ответы
Ответ 1
Это хороший сложный вопрос, и вот сложный ответ.
> x <- "This Jon dogs' 'bout there in Mike re'y word."
> re <- "(?i)('?[a-z]){5,}(*SKIP)(?!)|('?[a-z]){4}'?"
> regmatches(x, gregexpr(re, x, perl=T))[[1]]
## [1] "This" "Jon's" "dogs'" "'bout" "word"
Объяснение
Идея состоит в пропустить любые шаблоны слов, которые состоят из 5 или более буквенных символов и необязательного апострофа.
В левой части оператора чередования мы сопоставляем подшаблон, который нам не нужен.
Препятствие и принуждение механизма регулярных выражений не повторять подстроку с помощью управления обратным трассированием. Как поясняется ниже:
(*SKIP) # advances to the position in the string where (*SKIP) was
# encountered signifying that what was matched leading up
# to cannot be part of the match
(?!) # equivalent to (*FAIL), causes matching failure,
# forcing backtracking to occur
Правая часть оператора чередования соответствует желаемому...
Дополнительное объяснение:
-
По существу, в простых выражениях вы используете метод discard.
(?:'?[a-z]){5,}|((?:'?[a-z]){4}'?)
Вы используете оператор чередования в контексте, помещая то, что вы хотите исключить слева (говорящий выбросить его, это мусор) и поместите то, что вы хотите сопоставить, в > с правой стороны.
Ответ 2
Вы можете использовать этот шаблон:
(?i)(?<![a-z'])(?:'?[a-z]){4}'?(?![a-z'])
Ответ 3
Вы можете использовать метод отбрасывания и использовать регулярное выражение следующим образом:
\b\w{0,2}\b(?:'\w)?|\b\w{3}(?!')\b|\b\w{5,}\b|('?\b\w+\b'?\w?)
Рабочая демонстрация
![enter image description here]()
MATCH 1
1. [0-4] `This`
MATCH 2
1. [5-10] `Jon's`
MATCH 3
1. [11-16] `dogs'`
MATCH 4
1. [17-22] `'bout`
MATCH 5
1. [32-36] `word`
Для R необходимо избегать специальных символов.
Как вы можете видеть в шаблоне регулярных выражений, вы можете использовать все, что вам не нужно в левой части шаблона, и оставлять то, что вы действительно хотите, в группе захвата с самой правой стороны. Идея техники отказа:
discard this|don't want this|still don't care this|(Oh yeah! I grab this)
СПАСИБО EdConttrell и johnwait, чтобы помочь мне улучшить ответ.
Ответ 4
EDITED дважды: (спасибо hex494D49):
(?i)(?<=\W|^)(?<!')'*(?:\w{4}|\w'*\w{3}|\w{2}'*\w{2}|\w{3}'*\w|\w{2}'*\w'*\w|\w'*\w{2}'*\w|\w'*\w'*\w{2}|\w'*\w'*\w'*\w)'*(?!')(?=\W|$)
Лучше пойдите для всех возможных случаев...
Но название вопроса:
grab n letter words don't count apostrophes regex
Поэтому я бы не рекомендовал мое решение.
Ответ 5
Другое решение, которое, я думаю, может быть немного яснее/более кратким:
Regex
(?<![\w'])(?:'?\w'?){4}(?![\w'])
Объяснение
(?<![\w'])
Это отрицательное утверждение: он проверяет, что совпадению не предшествует '
char или слово char (\w
совпадает с [a-zA-Z]
).
(?:'?\w'?){4}
Это соответствует любому слову char, опционально которому предшествует/преследуется '
. (?: ... )
делает группу не захватывающей.
(?![\w'])
Это утверждение Negative Lookahead, гарантирующее, что за группой не следует другой апостроф или буква char.
Цель первого и последнего условий состоит в том, чтобы убедиться, что 4 совпадения по средней группе не окружены большим количеством символов: т.е. Слово имеет только 4 буквы.
Они более или менее эквивалентны обнаружению границы слова \b
, за исключением того, что они считают апостроф частью слова, которое \b
не имеет.
Вопросы
Регулярное выражение не будет соответствовать строкам, которые начинаются или заканчиваются двойными апострофами, ''
. Я не думаю, что это огромная потеря.
Пример
См. эту ссылку на regex101.com.