У меня есть вектор регулярных выражений, включающий набор/диапазон чисел. Я хочу преобразовать каждое выражение в вектор строк, который явно описывает каждое совпадение. Например, учитывая x
, мне нужен результат ниже. Я также пробовал следующее, но не смог заставить его работать. Есть ли способ добиться того, чего я хочу?
данные
x <- c("N17[0-3]", "438[46]", "I6[02-45]1", "V[1-3]71")
хотеть
"N170", "N171", "N172", "N173", "4384", "4386", "I601", "I621", "I631", "I641", "I651", "V171", "V271", "V371"
пытался
x_split <- strsplit(x, "")
lapply(x_split, function(y) {
bracket1_idx <- which(y == "[")
bracket2_idx <- which(y == "]")
num1 <- y[bracket1_idx+1]
num2 <- y[bracket2_idx-1]
substr1 <- y[1:bracket1_idx-1] |> paste0(collapse = "")
if (bracket2_idx == length(y)) paste0(substr1, seq(num1, num2))
else {
substr2 <- y[(bracket2_idx+1):length(y)] |> paste0(collapse = "")
paste0(substr1, seq(num1, num2), substr2)
}
})
Есть пакет Python exrex, который делает именно то, что вы описываете:
Exrex — это инструмент командной строки и модуль Python, который генерирует все или случайные строки, соответствующие заданному регулярному выражению и многим другим.
Возможно, это лениво, или, если хотите, вы можете сказать, что он более надежен и, возможно, лучше справляется с крайними случаями, чем развертывание собственного решения, но я бы просто установил его с терминала:
# Assuming Python is already installed
pip install exrex
Затем вы можете взаимодействовать с инструментом командной строки из R:
exrex <- function(l) {
lapply(l, \(x) processx::run("exrex", x))
}
# [[1]]
# [1] "N170" "N171" "N172" "N173"
# [[2]]
# [1] "4384" "4386"
# [[3]]
# [1] "I601" "I621" "I631" "I641" "I651"
# [[4]]
# [1] "V171" "V271" "V371"
Вы можете unlist()
возвращаемое значение, если хотите.
Я предпочитаю processx , так как он правильно экранирует строки и обрабатывает пробелы. См. Сохранение результата системного вызова в объекте R для сравнения с system()
и system2()
. Если у вас нет места и вам не нужен дополнительный пакет, вы можете сделать это следующим образом:
exrex <- function(l) {
lapply(
l,
\(x) system2("exrex", args = shQuote(x), stdout = TRUE)
)
}
exrex(x)
# same output
shQuote() означает, что строки, содержащие кавычки типа "N17\"[0-4]"
, будут правильно экранированы. Однако даже с shQuote()
ни system()
, ни system2()
не будут правильно обрабатывать строки с пробелами.
Сначала замените цифру, минус, цифру последовательностью цифр в строке gsubfn
, а затем в следующей строке создайте список векторов и, наконец, удалите его из списка.
library(gsubfn)
x |>
gsubfn("(\\d)-(\\d)", ~ paste(seq(x, y), collapse = ""), x = _) |>
strapply("(.*)\\[(\\d*)\\](.*)", ~ paste0(x, strsplit(y, "")[[1]], z)) |>
unlist()
## [1] "N170" "N171" "N172" "N173" "4384" "4386" "I601" "I621" "I631" "I641" "I651" "V171"
## [13] "V271" "V371"
Вот подход с использованием базы R:
patterns <- regmatches(x, regexpr("\\[.*\\]", x))
replacements <- sapply(patterns, \(v) grep(v, 0:9, value = TRUE))
mapply(sub,
rep(patterns, lengths(replacements)),
unlist(replacements),
rep(x, lengths(replacements)),
fixed = TRUE,
USE.NAMES = FALSE)
[1] "N170" "N171" "N172" "N173" "4384" "4386" "I601" "I621" "I631" "I641" "I651" "V171" "V271"
[14] "V371"