online - Captura del grupo Regex en R con múltiples grupos de captura
regular expression creator online (8)
En R, ¿es posible extraer la captura de grupo de una coincidencia de expresión regular? Por lo que puedo decir, ninguno de grep
, grepl
, regexpr
, gregexpr
, sub
o gsub
devuelve las capturas de grupo.
Necesito extraer pares clave-valor de cadenas que están codificadas así:
/((.*?) :: (0/.[0-9]+)/)
Siempre puedo hacer múltiples greps de partido completo, o hacer un poco de procesamiento externo (que no sea R), pero esperaba poder hacerlo todo dentro de R. ¿Hay alguna función o paquete que brinde esa función para hacer esto?
Así es como terminé trabajando en torno a este problema. Usé dos expresiones regulares separadas para hacer coincidir el primer y el segundo grupo de captura y ejecutar dos llamadas gregexpr
, y luego sacar las subcadenas coincidentes:
regex.string <- "(?<=//().*?(?= :: )"
regex.number <- "(?<= :: )//d//.//d+"
match.string <- gregexpr(regex.string, str, perl=T)[[1]]
match.number <- gregexpr(regex.number, str, perl=T)[[1]]
strings <- mapply(function (start, len) substr(str, start, start+len-1),
match.string,
attr(match.string, "match.length"))
numbers <- mapply(function (start, len) as.numeric(substr(str, start, start+len-1)),
match.number,
attr(match.number, "match.length"))
Como se sugiere en el paquete stringr
, esto se puede lograr usando str_match()
o str_extract()
.
Adaptado del manual:
library(stringr)
strings <- c(" 219 733 8965", "329-293-8753 ", "banana",
"239 923 8115 and 842 566 4692",
"Work: 579-499-7527", "$1000",
"Home: 543.355.3679")
phone <- "([2-9][0-9]{2})[- .]([0-9]{3})[- .]([0-9]{4})"
Extrayendo y combinando nuestros grupos:
str_extract(strings, phone)
# [1] "219 733 8965" "329-293-8753" NA "239 923 8115" "579-499-7527" NA
# [7] "543.355.3679"
Indicando grupos con una matriz de salida (estamos interesados en las columnas 2+):
str_match(strings, phone)
# [,1] [,2] [,3] [,4]
# [1,] "219 733 8965" "219" "733" "8965"
# [2,] "329-293-8753" "329" "293" "8753"
# [3,] NA NA NA NA
# [4,] "239 923 8115" "239" "923" "8115"
# [5,] "579-499-7527" "579" "499" "7527"
# [6,] NA NA NA NA
# [7,] "543.355.3679" "543" "355" "3679"
Me gustan las expresiones regulares compatibles con Perl. Probablemente alguien más lo haga también ...
Aquí hay una función que hace expresiones regulares perl compatibles y coincide con la funcionalidad de funciones en otros idiomas a los que estoy acostumbrado:
regexpr_perl <- function(expr, str) {
match <- regexpr(expr, str, perl=T)
matches <- character(0)
if (attr(match, ''match.length'') >= 0) {
capture_start <- attr(match, ''capture.start'')
capture_length <- attr(match, ''capture.length'')
total_matches <- 1 + length(capture_start)
matches <- character(total_matches)
matches[1] <- substr(str, match, match + attr(match, ''match.length'') - 1)
if (length(capture_start) > 1) {
for (i in 1:length(capture_start)) {
matches[i + 1] <- substr(str, capture_start[[i]], capture_start[[i]] + capture_length[[i]] - 1)
}
}
}
matches
}
Pruebe los regmatches()
y regexec()
:
regmatches("(sometext :: 0.1231313213)",regexec("//((.*?) :: (0//.[0-9]+)//)","(sometext :: 0.1231313213)"))
[[1]]
[1] "(sometext :: 0.1231313213)" "sometext" "0.1231313213"
Solución con strcapture
de los utils
:
x <- c("key1 :: 0.01",
"key2 :: 0.02")
strcapture(pattern = "(.*) :: (0//.[0-9]+)",
x = x,
proto = list(key = character(), value = double()))
#> key value
#> 1 key1 0.01
#> 2 key2 0.02
gsub () puede hacer esto y devolver solo el grupo de captura:
Sin embargo, para que esto funcione, debe seleccionar explícitamente elementos fuera de su grupo de captura como se menciona en la ayuda de gsub ().
(...) los elementos de los vectores de caracteres ''x'' que no están sustituidos se devolverán sin cambios.
Por lo tanto, si el texto que va a seleccionar se encuentra en el medio de una cadena, agregar. * Antes y después del grupo de captura debería permitirle solo devolverlo.
gsub(".*//((.*?) :: (0//.[0-9]+)//).*","//1 //2", "(sometext :: 0.1231313213)") [1] "sometext 0.1231313213"
gsub lo hace, de tu ejemplo:
gsub("//((.*?) :: (0//.[0-9]+)//)","//1 //2", "(sometext :: 0.1231313213)")
[1] "sometext 0.1231313213"
necesita duplicar el escape en las comillas, entonces funcionan para la expresión regular.
Espero que esto ayude.
str_match()
, del paquete stringr
, hará esto. Devuelve una matriz de caracteres con una columna para cada grupo en el partido (y una para el partido completo):
> s = c("(sometext :: 0.1231313213)", "(moretext :: 0.111222)")
> str_match(s, "//((.*?) :: (0//.[0-9]+)//)")
[,1] [,2] [,3]
[1,] "(sometext :: 0.1231313213)" "sometext" "0.1231313213"
[2,] "(moretext :: 0.111222)" "moretext" "0.111222"