Вы можете использовать аргументы start/end_escape
для предоставления LHS и RHS сопоставленных разделителей, таких как {
и }
, не сопоставляя их в неправильном месте (}
в качестве разделителя LHS)
perl = TRUE
позволяет проверять утверждения. Они оценивают достоверность утверждений внутри них , не фиксируя их в шаблоне . Этот пост довольно хорошо их охватывает.
Вы получите ошибку в perl = FALSE
, потому что TRE , механизм регулярных выражений по умолчанию для R, не поддерживает их.
gsub3 <- function(pattern, replacement, x, escape = NULL, start_escape = NULL, end_escape = NULL) {
if (!is.null(escape) || !is.null(start_escape))
left_escape <- paste0("(?<![", paste0(escape, paste0(start_escape, collapse = ""), collapse = ""), "])")
if (!is.null(escape) || !is.null(end_escape))
right_escape <- paste0("(?![", paste0(escape, paste0(end_escape, collapse = ""), collapse = ""), "])")
patt <- paste0(left_escape, "(", pattern, ")", right_escape)
gsub(patt, replacement, x, perl = TRUE)
}
gsub3("banana", "potatoe", "'banana' banana \"banana\"", escape = "'\"")
#> [1] "'banana' potatoe \"banana\""
gsub3("banana", "potatoe", "'banana' apple \"banana\"", escape = '"\'')
#> [1] "'banana' apple \"banana\""
gsub3("banana", "potatoe", "{banana} banana {banana}", escape = "{}")
#> [1] "{banana} potatoe {banana}"
gsub3("banana", "potatoe", "{banana} apple {banana}", escape = "{}")
#> [1] "{banana} apple {banana}"
Ниже grepl3
- обратите внимание, что для этого не нужно perl = TRUE
, так как нам все равно, что захватывает образец, только то, что он соответствует.
grepl3 <- function(pattern, x, escape = "'", start_escape = NULL, end_escape = NULL) {
if (!is.null(escape) || !is.null(start_escape))
start_escape <- paste0("[^", paste0(escape, paste0(start_escape, collapse = ""), collapse = ""), "]")
if (!is.null(escape) || !is.null(end_escape))
end_escape <- paste0("[^", paste0(escape, paste0(end_escape, collapse = ""), collapse = ""), "]")
patt <- paste0(start_escape, pattern, end_escape)
grepl(patt, x)
}
grepl3("banana", "'banana' banana \"banana\"", escape =c('"', "'"))
#> [1] TRUE
grepl3("banana", "'banana' apple \"banana\"", escape =c('""', "''"))
#> [1] FALSE
grepl3("banana", "{banana} banana {banana}", escape = "{}")
#> [1] TRUE
grepl3("banana", "{banana} apple {banana}", escape = "{}")
#> [1] FALSE
Редактировать:
Это должно решить gsub без проблем, упомянутых Эндрю, если у вас все в порядке с одним набором парных операторов. Я думаю, что вы можете изменить его, чтобы разрешить несколько разделителей. Спасибо за увлекательную проблему, нашла новый драгоценный камень в regmatches
!
gsub4 <-
function(pattern,
replacement,
x,
left_escape = "{",
right_escape = "}") {
# `regmatches()` takes a character vector and
# output of `gregexpr` and friends and returns
# the matching (or unmatching, as here) substrings
string_pieces <-
regmatches(x,
gregexpr(
paste0(
"\\Q", # Begin quote, regex will treat everything after as fixed.
left_escape,
"\\E(?>[^", # \\ ends quotes.
left_escape,
right_escape,
"]|(?R))*", # Recurses, allowing nested escape characters
"\\Q",
right_escape,
"\\E",
collapse = ""
),
x,
perl = TRUE
), invert =NA) # even indices match pattern (so are escaped),
# odd indices we want to perform replacement on.
for (k in seq_along(string_pieces)) {
n_pieces <- length(string_pieces[[k]])
# Due to the structure of regmatches(invert = NA), we know that it will always
# return unmatched strings at odd values, padding with "" as needed.
to_replace <- seq(from = 1, to = n_pieces, by = 2)
string_pieces[[k]][to_replace] <- gsub(pattern, replacement, string_pieces[[k]][to_replace])
}
sapply(string_pieces, paste0, collapse = "")
}
gsub4('banana', 'apples', "{banana's} potatoes {banana} banana", left_escape = "{", right_escape = "}")
#> [1] "{banana's} potatoes {banana} apples"
gsub4('banana', 'apples', "{banana's} potatoes {banana} banana", left_escape = "{", right_escape = "}")
#> [1] "{banana's} potatoes {banana} apples"
gsub4('banana', 'apples', "banana's potatoes", left_escape = "{", right_escape = "}")
#> [1] "apples's potatoes"
gsub4('banana', 'apples', "{banana's} potatoes", left_escape = "{", right_escape = "}")
#> [1] "{banana's} potatoes"