(跳过)(失败)使用 stringi 解析错误

(Skip)(Fail) Parse error with stringi

我是 reading/learning The Greatest Regex Trick Ever 我们说我们想要一些东西除非...使用 (*SKIP)(*FAIL)。好的,所以我试了一下下面的玩具示例,它在 base R 中工作,但在 stringi 中有以下错误。我是否需要对 stringi 做一些不同的事情才能使语法正常工作?

x <- c("I shouldn't", "you should", "I know", "'bout time")
pat <- '(?:houl)(*SKIP)(*FAIL)|(ou)'

grepl(pat, x, perl = TRUE)
## [1] FALSE  TRUE FALSE  TRUE

stringi::stri_detect_regex(x, pat)
## Error in stringi::stri_detect_regex(x, pat) : 
##   Syntax error in regexp pattern. (U_REGEX_RULE_SYNTAX)

stringi 模块(以及 stringr)与 ICU regex library 捆绑在一起,不支持 (*SKIP)(*FAIL) 动词(它们实际上仅受 PCRE 库支持).

由于您匹配的 ou 前面没有 h,后面也没有 l,您可以使用通常的环视:

(?<!h)ou(?!l)

regex demo

> x <- c("I shouldn't", "you should", "I know", "'bout time")
> pat1 <- "(?<!h)ou(?!l)"
> stringi::stri_detect_regex(x, pat1)
[1] FALSE  TRUE FALSE  TRUE

我还可以在这里建议另一种方法。由于您的代码暗示您只想 return 一个布尔值,指示字符串中是否有 ou 而不是 houl,您可以使用

stringi::stri_detect_regex(x, "^(?!.*houl).*ou")

another regex demo

详情

  • ^ - 字符串的开头
  • (?!.*houl) - 如果在字符串开头之后有 0+ 个字符而不是换行符,则匹配失败的否定前瞻尽可能多地后跟 houl
  • .*- 0+ 换行字符以外的字符尽可能多
  • ou - ou 子串。

有关 Lookahead and Lookbehind Zero-Length Assertions 的更多详细信息。

请注意,在 ICU 中,lookbehind 不能包含未知宽度的模式,但是,lookbehind 中的限制量词是受支持的。所以,在 stringi 中,如果你想匹配任何包含 ou 且左边某处没有以 s 开头的单词,你可以使用

> pat2 <- "(?<!s\w{0,100})ou"
> stringi::stri_detect_regex(x, pat2)
[1] FALSE  TRUE FALSE  TRUE

如果 (?<!s\w{0,100}) constrained-width lookbehind 匹配失败,如果 ou 前面是 s 后跟 0 到 100 字母数字或下划线字符。