(Пропустить)(Сбой) Ошибка синтаксического анализа со строкой

Я читал/изучал Величайший трюк с регулярными выражениями, где мы говорим, что хотим чего-то, если ...используя (*SKIP)(*FAIL). Итак, я попробовал его на игрушечном примере ниже, и он работает в базе 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)

person Tyler Rinker    schedule 14.01.2016    source источник
comment
stringi использует вариант регулярного выражения ICU, который не поддерживает управляющие глаголы, такие как (*SKIP) и (*FAIL). Они основали его на разновидности Java, поэтому версия Trick для Java (такая, какая она есть) должна работать.   -  person Alan Moore    schedule 15.01.2016
comment
Вы тоже можете использовать этот трюк: ou(?:(?!l)|(?<!hou)). Преимущество в том, что паттерн начинается с буквальной строки (что ускоряет исследование), а обходные пути проверяются только после этого.   -  person Casimir et Hippolyte    schedule 15.01.2016
comment
@AlanMoore познавательно, спасибо, я не смог найти эквивалент jave. Я попробовал stringi::stri_detect_regex(x, 'houl|(ou)'), но это дает: [1] TRUE TRUE FALSE TRUE, где он должен потерпеть неудачу на первом элементе.   -  person Tyler Rinker    schedule 15.01.2016
comment
Попробуйте использовать stackoverflow. ком/вопросы/24534782/   -  person gagolews    schedule 07.02.2016


Ответы (1)


Модуль stringi (а также stringr) связан с библиотекой регулярных выражений ICU и (*SKIP)(*FAIL) глаголы не поддерживаются (на самом деле они поддерживаются только библиотекой PCRE).

Поскольку вы сопоставляете ou, которым не предшествует h и за которыми не следует l, вы можете использовать обычные обходные пути:

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

См. демонстрацию регулярного выражения.

> 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

Здесь я также могу предложить другой подход. Поскольку ваш код подразумевает, что вы хотите просто вернуть логическое значение, указывающее, есть ли ou внутри строки, но не houl, вы можете использовать

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

См. другую демонстрацию регулярного выражения

Подробнее

  • ^ - начало строки
  • (?!.*houl) - отрицательный просмотр вперед, который не дает совпадения, если сразу после начала строки есть 0+ символов, отличных от символов разрыва строки, как можно больше, за которыми следует houl
  • .*- 0+ символов, отличных от символов разрыва строки, как можно больше
  • ou - подстрока ou.

Дополнительные сведения см. в разделе упреждающие и ретроспективные утверждения нулевой длины.

Обратите внимание, что в ICU просмотр назад не может содержать шаблоны неизвестной ширины, однако поддерживаются ограничивающие квантификаторы внутри просмотра назад. Итак, в stringi, если вы хотите сопоставить любое слово, содержащее ou, которому не предшествует s где-то слева, вы можете использовать

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

Где (?<!s\\w{0,100}) обратный просмотр с ограниченной шириной не соответствует совпадению, если ou предшествует s, за которым следует от 0 до 100 буквенно-цифровых символов или символов подчеркивания.

person Wiktor Stribiżew    schedule 26.05.2016