【问题标题】:R: lookaround within lookaroundR:环视内环视
【发布时间】:2015-06-18 18:53:25
【问题描述】:

我需要匹配前面有两个不同元音的任何“r”。例如,'our' 或 'pear' 会匹配,但 'bar' 或 'aar' 不会。我确实设法匹配了两个不同的元音,但我仍然无法使后面的“r”成为条件(...)。 (?<=...)r 和 ...\\Kr 都不会产生任何结果。有什么想法吗?

x <- c('([aeiou])(?!\\1)(?=(?1))')
y <- c('our','pear','bar','aar')
y[grepl(paste0(x,collapse=''),y,perl=T)]
## [1] "our"  "pear"`

【问题讨论】:

  • skip&fail 动词的经典用例:regex101.com/r/qC9kO2/1
  • 蛮力方法:combos&lt;-combn(c("a","e","i","o","u"),2);grepl(paste0("(",paste(c(paste0(combos[1,],combos[2,]),paste0(combos[2,],combos[1,])),collapse="|"),")r"),y)。很丑,觉得还不够好回答:)
  • @HamZa,为什么不回答?
  • @Pouya 我在玩。这只是一个评论,而不是一个完整的答案。您可以通过解释对其进行扩展并将其作为答案发布。
  • 感谢@HamZa 的解决方案和解释!

标签: regex r backreference


【解决方案1】:

这是一个不太优雅的解决方案:

y[grepl("[aeiou]{2}r", y, perl=T) & !grepl("(.)\\1r", y, perl=T)]

可能有一些极端情况失败,其中第一组匹配的位置与第二组不同(必须考虑这一点),但可以帮助您开始。

【讨论】:

  • 我喜欢这种方法。大多数时候,我们可以通过将其分解为两个或多个进程(正则表达式)来简化流程+1
  • 我认为(?!(.)\1)[aeiou]{2}r 会更好 - 模式有点复杂,但代码更简单。
  • @Kobi,您的模式不会做同样的事情,并且会匹配“bcaar”之类的东西。正确的做法是像 Casimir 所展示的那样。
  • 你大错特错了。我认为这是您的代码的问题,它不会接受bbraer(正如您在回答中所说的那样)。
  • @Kobi,非常有趣,将其解读为向后看而不是向前看。不过,在精神上与卡西米尔的相似,对吧?
【解决方案2】:

这两种解决方案似乎有效:

为什么不方式:

x <- '(?<=a[eiou]|e[aiou]|i[aeou]|o[aeiu]|u[aeio])r'
y[grepl(x, y, perl=T)]

\K 方式:

x <- '([aeiou])(?!\\1)[aeiou]\\Kr'
y[grepl(x, y, perl=T)]

why not方式变体(可能更高效,因为它之前搜索“r”):

x <- 'r(?<=a[eiou]r|e[aiou]r|i[aeou]r|o[aeiu]r|u[aeio]r)'

或快速排除前面没有两个元音的“r”(不测试整个交替)

x <- 'r(?<=[aeiou][aeiou]r)(?<=a[eiou]r|e[aiou]r|i[aeou]r|o[aeiu]r|u[aeio]r)'

【讨论】:

  • 谢谢!第二个选项看起来不错。
  • 我们也可以使用递归来缩短模式。对菜鸟不太友好:([aeiou])(?!\\1)(?1)\\Kr
  • @HamZa:也不是很有用,但我们可以。
  • 我删除了c() 和paste(collapse=""),因为它们似乎没有必要。如果需要这些元素,请随意回滚。
  • @dasf 我明白你为什么要这样做。如果这就是您正在做的所有事情,那么只需将该组写出两次可能会更短且更不容易出错。否则,您将处理更多的引号和逗号,并且更容易搞砸。但是维护起来并不容易,因为如果您想在将来更改它,您需要在两个位置进行更改,而不仅仅是一个。因此,无论哪种方式都需要权衡取舍。话虽如此,如果您在两个以上的地方使用它,那可能是要走的路。
【解决方案3】:

正如 HamZa 在 cmets 中指出的那样,使用跳过和失败动词是实现我们想要的一种方式。基本上我们告诉它忽略我们有两个相同的元音后跟“r”的情况

# The following is the beginning of the regex and isn't just R code
# the ([aeiou]) captures the first vowel, the \\1 references what we captured
# so this gives us the same vowel two times in a row
# which we then follow with an "r"
# Then we tell it to skip/fail for this
([aeiou])\\1r(*SKIP)(*FAIL)

现在我们告诉它跳过那些情况,所以现在我们告诉它“或者我们有两个元音后跟一个 'r' 的情况”,因为我们已经消除了这两个元音相同的情况,所以我们会得到什么我们想要。

|[aeiou]{2}r

把它放在一起,我们最终得到了

y <- c('our','pear','bar','aar', "aa", "ae", "are", "aeer", "ssseiras")
grep("([aeiou])\\1r(*SKIP)(*FAIL)|[aeiou]{2}r", y, perl = TRUE, value = TRUE)
#[1] "our"    "pear"    "sseiras"

【讨论】:

  • 感谢您的解释。我觉得这在未来会非常有用。
【解决方案4】:

另一个通过否定前瞻断言。

> y <- c('our','pear','bar','aar', "aa", "ae", "are", "aeer", "ssseiras")
> grep("(?!(?:aa|ee|ii|oo|uu)r)[aeiou][aeiou]r", y, perl=TRUE, value=TRUE)
[1] "our"      "pear"     "ssseiras"

> grep("(?!aa|ee|ii|oo|uu)[aeiou][aeiou]r", y, perl=TRUE, value=TRUE)
[1] "our"      "pear"     "ssseiras"

(?!aa|ee|ii|oo|uu) 断言匹配中的前两个字符不会是 aa 或 ee 或 .... 或 uu。所以这个[aeiou][aeiou] 会匹配其他任何两个元音,但不会重复。这就是我们首先设置条件的原因。 r 匹配元音后面的 r。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-11
    • 1970-01-01
    • 1970-01-01
    • 2019-08-20
    • 1970-01-01
    相关资源
    最近更新 更多