Prueba si los caracteres en cadena en R

Estoy tratando de determinar si una cadena es un subconjunto de otra cadena. Por ejemplo:

chars <- "test" value <- "es" 

Quiero devolver TRUE si “value” aparece como parte de la cadena “chars”. En el siguiente escenario, me gustaría devolver falso:

 chars <- "test" value <- "et" 

Usa la función grepl

 grepl(value, chars) # TRUE 

Responder

Suspiro, me tomó 45 minutos encontrar la respuesta a esta simple pregunta. La respuesta es: grepl(needle, haystack, fixed=TRUE)

 # Correct > grepl("1+2", "1+2", fixed=TRUE) [1] TRUE > grepl("1+2", "123+456", fixed=TRUE) [1] FALSE # Incorrect > grepl("1+2", "1+2") [1] FALSE > grepl("1+2", "123+456") [1] TRUE 

Interpretación

grep recibe su nombre del ejecutable de Linux, que es en sí mismo un acrónimo de ” P ro g elación de E xpresión R egular G obular”, leía líneas de entrada y luego las imprimía si coincidían con los argumentos que usted daba. “Global” significaba que la coincidencia podía ocurrir en cualquier lugar de la línea de entrada, explicaré “Regular Expression” a continuación, pero la idea es que es la forma más inteligente de hacer coincidir la cadena (R llama a este “personaje”, por ejemplo, class("abc") ), e “Imprimir” porque es un progtwig de línea de comando, emitir salida significa que se imprime a su cadena de salida.

Ahora, el progtwig grep es básicamente un filtro, desde líneas de entrada, hasta líneas de salida. Y parece que la función grep de R también tomará una serie de entradas. Por razones que son totalmente desconocidas para mí (solo comencé a jugar con R hace aproximadamente una hora), devuelve un vector de los índices que coinciden, en lugar de una lista de coincidencias.

Pero, de vuelta a su pregunta original, lo que realmente queremos es saber si encontramos la aguja en el pajar, un valor verdadero / falso. Al parecer, decidieron nombrar esta función como grep, como en “grep” pero con un valor de retorno “Lógico” (llaman valores lógicos verdaderos y falsos, por ejemplo, class(TRUE) ).

Entonces, ahora sabemos de dónde viene el nombre y qué se supone que debe hacer. Volvamos a las expresiones regulares. Los argumentos, a pesar de que son cadenas, se usan para construir expresiones regulares (a partir de ahora: regex). Una expresión regular es una forma de hacer coincidir una cuerda (si esta definición te irrita, déjala ir). Por ejemplo, la expresión regular a coincide con el carácter "a" , la expresión regular a* coincide con el carácter "a" 0 o más veces, y la expresión regular a+ concuerda con el carácter "a" 1 o más veces. Por lo tanto, en el ejemplo anterior, la aguja que estamos buscando 1+2 , cuando se trata como una expresión regular, significa “uno o más 1 seguido de un 2” … ¡pero el nuestro es seguido por un más!

1 + 2 como expresión regular

Por lo tanto, si usaba el grepl sin configuración fixed , sus agujas serían accidentalmente pajares, y eso funcionaría accidentalmente bastante a menudo, podemos ver que incluso funciona para el ejemplo del OP. ¡Pero eso es un error latente! Necesitamos decirle que la entrada es una cadena, no una expresión regular, que aparentemente es para lo que se fixed . ¿Por qué arreglado? No hay pista, marque esta respuesta b / c, probablemente tendrá que buscarla 5 veces más antes de memorizarla.

Algunas reflexiones finales

Cuanto mejor sea tu código, menos historia tienes que saber para darle sentido. Cada argumento puede tener al menos dos valores interesantes (de lo contrario no necesitaría ser un argumento), los documentos listan 9 argumentos aquí, lo que significa que hay al menos 2 ^ 9 = 512 maneras de invocarlo, eso es mucho trabajo para escriba, pruebe y recuerde … desacople tales funciones (divídalas, elimine las dependencias entre sí, las cosas de la secuencia son diferentes a las expresiones regulares que son diferentes a las del vector). Algunas de las opciones también son mutuamente excluyentes, no le dan a los usuarios formas incorrectas de usar el código, es decir, la invocación problemática debe ser estructuralmente absurda (como pasar una opción que no existe), no es lógicamente absurda (donde usted tiene que emitir una advertencia para explicarlo). Puesto metafóricamente: reemplazar la puerta de entrada en el lado del décimo piso con una pared es mejor que colgar un letrero que advierta contra su uso, pero cualquiera es mejor que ninguno de los dos. En una interfaz, la función define cómo deberían ser los argumentos, no la persona que llama (porque la persona que llama depende de la función, deducir todo aquello con lo que todos desearían llamar, hace que la función dependa también de las personas que llaman, y este tipo de dependencia cíclica obstruirá rápidamente un sistema y nunca proporcionará los beneficios que espera). Tenga mucho cuidado con los tipos equívocos, es un defecto de diseño que cosas como TRUE y 0 y "abc" son todos vectores.

Quieres grepl :

 > chars <- "test" > value <- "es" > grepl(value, chars) [1] TRUE > chars <- "test" > value <- "et" > grepl(value, chars) [1] FALSE 

Use esta función del paquete stringi :

 > stri_detect_fixed("test",c("et","es")) [1] FALSE TRUE 

Algunos puntos de referencia:

 library(stringi) set.seed(123L) value <- stri_rand_strings(10000, ceiling(runif(10000, 1, 100))) # 10000 random ASCII strings head(value) chars <- "es" library(microbenchmark) microbenchmark( grepl(chars, value), grepl(chars, value, fixed=TRUE), grepl(chars, value, perl=TRUE), stri_detect_fixed(value, chars), stri_detect_regex(value, chars) ) ## Unit: milliseconds ## expr min lq median uq max neval ## grepl(chars, value) 13.682876 13.943184 14.057991 14.295423 15.443530 100 ## grepl(chars, value, fixed = TRUE) 5.071617 5.110779 5.281498 5.523421 45.243791 100 ## grepl(chars, value, perl = TRUE) 1.835558 1.873280 1.956974 2.259203 3.506741 100 ## stri_detect_fixed(value, chars) 1.191403 1.233287 1.309720 1.510677 2.821284 100 ## stri_detect_regex(value, chars) 6.043537 6.154198 6.273506 6.447714 7.884380 100 

En caso de que también desee comprobar si una cadena (o un conjunto de cadenas) contiene (n) múltiples cadenas secundarias, también puede utilizar el ‘|’ entre dos subcadenas.

 >substring="as|at" >string_vector=c("ass","ear","eye","heat") >grepl(substring,string_vector) 

Conseguirás

 [1] TRUE FALSE FALSE TRUE 

ya que la primera palabra tiene una subcadena “como”, y la última palabra contiene una subcadena “a”

Use grep o grepl pero tenga en cuenta si desea usar expresiones regulares o no .

Por defecto, grep y related toman una expresión regular para coincidir, no una subcadena literal. Si no está esperando eso, e intenta hacer coincidir una expresión regular no válida, no funciona:

 > grep("[", "abc[") Error in grep("[", "abc[") : invalid regular expression '[', reason 'Missing ']'' 

Para hacer una prueba de subcadena verdadera, use fixed = TRUE .

 > grep("[", "abc[", fixed = TRUE) [1] 1 

Si quieres expresiones regulares, genial, pero eso no es lo que el OP parece estar pidiendo.

Además, se puede hacer usando la biblioteca “stringr”:

 > library(stringr) > chars <- "test" > value <- "es" > str_detect(chars, value) [1] TRUE ### For multiple value case: > value <- c("es", "l", "est", "a", "test") > str_detect(chars, value) [1] TRUE FALSE TRUE FALSE TRUE 

Puedes usar grep

 grep("es", "Test") [1] 1 grep("et", "Test") integer(0)