抓住n个字母,不要算撇号正则表达式

时间:2014-08-11 00:22:16

标签: regex r

我正在努力更深入地学习R中的正则表达式。我给了自己一些我认为不容易理解的简单任务。我想提取所有4个字母的单词。在这四个字母的单词中我想忽略(不要算)撇号。我可以在没有正则表达式的情况下执行此操作但需要正则表达式解决方案这是一个MWE和我尝试过的:

text.var <- "This Jon's dogs' 'bout there in Mike's 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个字符的单词。

5 个答案:

答案 0 :(得分:16)

这是一个很有挑战性的问题,这是一个棘手的答案。

> x  <- "This Jon's dogs' 'bout there in Mike's 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

交替运算符的右侧符合我们想要的......

附加说明:

  • 从本质上讲,简单来说就是使用弃牌技术

    (?:'?[a-z]){5,}|((?:'?[a-z]){4}'?)
    

    你在上下文中使用交替运算符,在左边放置你要排除的内容,(说扔掉它,它是垃圾)并在capturing group中放置你想要匹配的内容在右侧。

答案 1 :(得分:11)

您可以使用此模式:

(?i)(?<![a-z'])(?:'?[a-z]){4}'?(?![a-z'])

答案 2 :(得分:8)

您可以使用弃牌技术并使用这样的正则表达式:

\b\w{0,2}\b(?:'\w)?|\b\w{3}(?!')\b|\b\w{5,}\b|('?\b\w+\b'?\w?)

<强> Working demo

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 帮助我改进答案。

答案 3 :(得分:5)

已编辑两次:(感谢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

所以我推荐我的解决方案。

答案 4 :(得分:4)

我认为另一种解决方案可能会更清晰/更简洁:

正则表达式

(?<![\w'])(?:'?\w'?){4}(?![\w'])

解释

(?<![\w'])

这是一个否定的Lookbehind断言:它检查匹配是否前面没有'字符或字符char(\w[a-zA-Z]相同)。

(?:'?\w'?){4}

这匹配任何单词char,可选地在'之前/之后。 (?: ... )使组无法捕获。

(?![\w'])

这是一个否定的前瞻断言,确保该组没有后跟另一个撇号或字母字符。


第一个和最后一个术语的目的是确保中间组的4个匹配不被更多字符包围:即该单词只有4个字母。

它们或多或少等同于\b字边界检测,除了它们将撇号计为\b没有的单词的一部分。

问题

正则表达式不会匹配以双撇号''开头或结尾的字符串。我不认为这是一个巨大的损失。

实施例

regex101.com上查看此链接。