Подтвердить что ты не робот

Захватить 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 символов.

4b9b3361

Ответ 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.