Un string es un fragmento de texto entre comillas.
mystring <- "some text"
mystring
#> [1] "some text"
typeof(mystring)
#> [1] "character"
Por desgracia, la terminología puede resultar confusa para quienes están familiarizados con otros lenguajes.
Aunque el type es character, R no distingue entre una sola letra (a la que en varios otros lenguajes se le llama char, pero no en R) y un string largo.
Ambos son un solo elemento y pueden ir entre comillas simples ' ' o dobles " " de manera intercambiable.
La guía de estilo recomienda usar comillas dobles, salvo cuando quieres usar comillas dobles dentro del string sin escaparlas.
str2 <- 'String with "quotes"' # convenience format
str2
#> [1] "String with \"quotes\"" # standard format
Un character vector es, entonces, un vector de strings, donde cada string es un solo elemento.
s <- c("some", "strings")
s
#> [1] "some" "strings"
length(s)
#> [1] 2
length(s[1]) # the number of vector elements, not the string length
#> [1] 1
nchar(s[1]) # the number of characters in the string "some"
#> [1] 4
En el ejemplo anterior, length(s[1]) equivale a length("some"): el número de elementos del vector, no la longitud del string.
Manipular un string individual es, obviamente, posible, como con nchar() en el ejemplo anterior, pero requiere funciones específicas que veremos más adelante.
Como vimos antes, algunos caracteres de puntuación deben «escaparse» anteponiéndoles una barra invertida \.
La lista no sorprenderá a la mayoría de quienes ya tienen experiencia programando, ya que este tema está bastante estandarizado entre lenguajes.
Además de las comillas (como se mostró antes), la lista incluye saltos de línea \n, tabulaciones \t, la barra invertida \\ y símbolos Unicode que empiezan con \U o \u.
Para evitar usar muchos caracteres de escape, es posible definir strings crudos dentro de r"( )":
r"(raw "string")"
#> [1] "raw \"string\""
Para los strings crudos que contienen paréntesis ( ), hay muchas otras opciones de sintaxis.
Cualquier versión de R con soporte actual codifica los strings en UTF-8, así que se puede dar soporte a la mayoría de los idiomas del mundo.
"आधुनिक मानक हिन्दी"
#> [1] "आधुनिक मानक हिन्दी"
Además, muchas funciones de R conocen el locale y tratan de seguir las convenciones locales para ordenar strings, convertir a mayúsculas o minúsculas, fechas y horas, etc.
Este temario mostrará ejemplos principalmente para el inglés de Estados Unidos: tanto porque es un valor predeterminado común como porque los autores del temario viven en Estados Unidos.
La configuración regional es un tema complejo, así que te recomendamos buscar documentación para tu propia situación.
Casi todo es posible en R base, pero a muchas personas que programan les parece que el soporte para manipular strings es más bien limitado y confuso.
Por suerte, existen paquetes de tidyverse mucho más intuitivos, flexibles y coherentes entre sí.
Todavía hay mucho código heredado que usa funciones de string al estilo antiguo. Esto incluye la mayoría de las soluciones de la comunidad en Exercism.
Además, para tareas pequeñas puede ser útil usar funciones integradas en lugar de importar una biblioteca grande. Quienes mantienen el track de R suelen adoptar este enfoque al escribir soluciones de ejemplo para validar los ejercicios de nuestro repositorio de GitHub.
Por lo tanto, todavía vale la pena aprender algo sobre los enfoques antiguos.
Las funciones que aparecen a continuación se presentan en su forma más simple, pero la mayoría también tiene argumentos opcionales. Consulta la documentación para más detalles.
ncharDevuelve el número de caracteres de un string.
nchar("string")
#> [1] 6
nchar("Hrōðgār") # a person in Beowulf, written in Old English
#> [1] 7
El tema (¡complicado!) de qué significa «carácter» queda fuera del alcance de esta página. Solo fíjate en un par de puntos de los ejemplos anteriores:
\0 (lo que sumaría 1 a la longitud).Ten cuidado con lo que le pasas a nchar.
Los resultados aún pueden ser impredecibles para valores que no son character, aunque esto ha mejorado en versiones recientes de R.
grepBusca un patrón en un vector de strings y devuelve los índices donde hay coincidencia.
grep("Jav", c("Java", "Python", "Javascript"))
#> [1] 1 3
paste and paste0
Combina una cantidad arbitraria de strings en un solo string.
De forma opcional, se puede especificar un separador para paste: el valor predeterminado es un espacio.
paste0(v) es equivalente a paste(v, sep = "").
paste("bits", "of", "a", "string")
#> [1] "bits of a string"
paste0("bits", "of", "a", "string")
#> [1] "bitsofastring"
sprintfPara tener un control más fino sobre el ensamblado de strings, R copia la función sprintf de C (y de varios lenguajes posteriores: Wikipedia enumera unos 30).
r <- 5.3
pi <- 3.14159
sprintf("A circle of radius %.1f has area %.2f", r, pi * r^2)
#> [1] "A circle of radius 5.3 has area 88.25"
trimwsLos espacios en blanco al principio o al final se pueden eliminar con trimws():
s <- " messy string "
trimws(s)
#> [1] "messy string"
Existe un parámetro which = "left" (o "right") para evitar recortar ambos extremos.
substrOpera sobre un solo string y devuelve el substring entre dos límites (inclusive).
substr("Exercism", 5, 7)
#> [1] "cis"
strsplitDivide un string en una lista de R, según un string separador. El separador es obligatorio (no tiene valor predeterminado), pero puede ser un string vacío.
strsplit("R, Python, Julia", ", ")
[[1]]
#> [1] "R" "Python" "Julia"
strsplit("Exercism", "")
[[1]]
#> [1] "E" "x" "e" "r" "c" "i" "s" "m"
Las listas se verán en un concepto aparte.
Si todavía no has llegado a esa parte del temario, por ahora basta con saber que la función unlist() (en este caso) convierte una lista en un vector.
unlist(strsplit("Exercism", ""))
#> [1] "E" "x" "e" "r" "c" "i" "s" "m"
regexpr and regexpr
Son la abreviatura de «expresión regular»: estas funciones buscan apariciones de un patrón en un string y devuelven una lista de datos (potencialmente) útiles. Solo las mencionamos para ser exhaustivos: ¡hay mejores opciones!
regexpr devuelve solo la primera aparición; gregexpr devuelve todas las apariciones (la «g» es de búsqueda «global»).
Como sugiere el nombre, el patrón puede ser una regex, que se verá en un concepto posterior.
¿Por qué estas viejas funciones de string se parecen a los comandos de shell de Unix?
Aunque R se creó en 1993, se diseñó para ser en gran medida compatible con versiones anteriores del lenguaje S.
S se diseñó en Bell Labs y apareció por primera vez en 1976. Bell Labs también fue responsable de Unix (desde 1969) y del lenguaje C (1972).
¡Vaya equipo el de aquella época tan anterior! Solo podemos suponer que hablaban entre sí e intercambiaban ideas.
Siendo generosos, podríamos decir que las funciones de string al estilo antiguo no son lo mejor que R tiene para ofrecer (hay opiniones menos generosas).
Para mejorar la situación, la biblioteca stringr está en desarrollo desde 2009 y ahora es una parte clave de la colección Tidyverse.
Impórtala en tu espacio de nombres con library(stringr) o library(tidyverse).
Algunas funcionalidades clave son:
str_ y tratan de dejar claro su propósito.Como todos los paquetes de Tidyverse, stringr tiene buena documentación, normalmente escrita por quienes crearon el paquete.
En stringr hay docenas de funciones disponibles y a menudo tienen una variedad de argumentos opcionales.
Al principio esto puede ser un poco abrumador, así que la documentación es tu mejor aliada.
Piensa en lo que quieres poner (¿un solo string? ¿un vector? ¿algo más complejo?) y en lo que quieres obtener.
Probablemente haya una manera fácil de hacer lo que quieras, siempre que encuentres la función correcta y los argumentos correctos.
El uso de los pipes |> para conectar funciones se tratará con más detalle en otras partes del temario.
Por ahora, es útil saber que:
El ejemplo de abajo ilustra la sintaxis. Las funciones individuales se verán más adelante.
library(stringr)
"Monday-25-February" |>
str_split("-") |>
unlist() |> # [1] "Monday" "25" "February"
str_sub(1, 3) |> # [1] "Mon" "25" "Feb"
str_to_upper() |> # [1] "MON" "25" "FEB"
str_flatten(collapse = ", ")
#> [1] "MON, 25, FEB"
str_length cuenta puntos de código (similar a nchars).
Otras varias funciones manipulan los espacios en blanco, como str_trim() y str_squish().
A menudo esta es una tarea de limpieza fundamental al inicio de cualquier proyecto de ciencia de datos.
# The first 3 kernels in JuPyteR notebooks:
str_length(c("Julia", "Python", "R")) #> [1] 1 6 5
#> [1] 5 6 1
str_pad(c("Julia", "Python", "R"), 8, "right") # add spaces if necessary
#> [1] "Julia " "Python " "R "
str_trim("Julia Python R ") # remove leading & trailing whitespace
#> [1] "Julia Python R"
str_squish("Julia Python R ") # trim, collapse multiple spaces
#> [1] "Julia Python R"
La función str_sub(string, start, end) devuelve el substring desde start hasta end (inclusive), mientras que str_sub_all() puede operar sobre varios strings a la vez.
Hay mucha flexibilidad.
start y end toman por defecto el primer y el último carácter, respectivamente.
Pueden ser vectores de índices.
A diferencia de la indexación de vectores (lo cual se agradece), los valores negativos cuentan desde el final del string, al estilo de Python.
s <- "abcdefgh"
str_sub(s, 2, 4)
#> [1] "bcd"
str_sub(s, 5)
#> [1] "efgh"
str_sub(s, -3, -2)
#> [1] "fg"
str_sub(s, c(1, 4), c(2, 5))
#> [1] "ab" "de"
str_sub(s, c(1, 4, 6), c(2, 5, -1))
#> [1] "ab" "de" "fgh"
s |> str_sub(2, 4) # these functions are designed for pipes
#> [1] "bcd"
# str_sub_all takes vector input, gives list output
str_sub_all(c(s, "ijklmnop"), c(1, 4, 6), c(2, 5, -1))
[[1]]
#> [1] "ab" "de" "fgh"
[[2]]
#> [1] "ij" "lm" "nop"
str_flatten convierte un vector de caracteres en un solo string.
El argumento collapse se inserta entre cada elemento y su valor predeterminado es "".
c("R", "Julia", "Python") |> str_flatten()
#> [1] "RJuliaPython"
c("R", "Julia", "Python") |> str_flatten(collapse = " - ")
#> [1] "R - Julia - Python"
str_c convierte varios vectores de caracteres en un solo vector de caracteres, con reciclaje cuando sea necesario.
str_c(LETTERS[1:8], 1:8, sep = ":")
#> [1] "A:1" "B:2" "C:3" "D:4" "E:5" "F:6" "G:7" "H:8"
str_glue trae a R una interpolación de strings sencilla.
Las expresiones dentro de las llaves { } se interpretan y se sustituye su representación como texto.
Si se proporcionan varios strings de expresiones, también se unirán como en str_flatten.
Además, de forma opcional se pueden recortar los espacios en blanco al principio o al final de los strings.
r <- 5.3
pi <- 3.14159
str_glue("A circle of radius {r} has area {pi * r^2}")
A circle of radius 5.3 has area 88.2472631
Aunque str_glue es flexible (y bastante complicada), la biblioteca subyacente glue ofrece una variedad aún mayor de posibilidades.
Un uso muy común de R es convertir datos desordenados en un formato consistente para su análisis. Para ayudarte con esto, hay varias maneras de dividir texto en substrings.
str_split_1 es la más simple: convierte un solo string en un vector de partes, dividiéndolo según algún patrón especificado (no hay patrón predeterminado).
s <- "R Julia Python"
str_split_1(s, " ")
#> [1] "R" "Julia" "Python"
str_split_i toma un vector de caracteres y un índice n, y devuelve un vector con el n-ésimo substring de cada string de entrada.
s2 <- c(s, "C Kotlin, F#") #> [1] "R Julia Python" "C Kotlin, F#"
str_split_i(s2, " ", 2) # 2nd element of each
#> [1] "Julia" "Kotlin,"
str_split toma un vector de caracteres y devuelve una lista de vectores.
En nuestro temario hay un concepto sobre listas que explica el resultado.
str_split(s2, " ")
[[1]]
#> [1] "R" "Julia" "Python"
[[2]]
#> [1] "C" "Kotlin," "F#"
También existe str_split_fixed, que devuelve una matriz.
Las matrices se verán en un concepto posterior.
Para comparar el string completo, str_equal() puede usar varias definiciones de «igualdad».
En el caso más simple, el valor predeterminado distingue entre mayúsculas y minúsculas, pero se puede cambiar.
La configuración regional y Unicode crean muchas más posibilidades.
str_equal("Odin", "odin")
#> [1] FALSE
str_equal("Odin", "odin", ignore_case = TRUE)
#> [1] TRUE
Hay muchas otras funciones, que se verán con más detalle en el concepto sobre expresiones regulares.
Algunos lenguajes (principalmente europeos) distinguen entre letras MAYÚSCULAS y minúsculas.
Hay un conjunto de funciones de stringr para convertir entre ambas de formas apropiadas para la configuración regional:
str_to_lower()str_to_upper()str_to_title() : la primera letra de cada palabra a mayúsculastr_to_sentence() : la primera letra de la oración a mayúsculastr_to_upper("elixir") # defaults to locale = "en"
#> [1] "ELIXIR"
str_to_upper("ελληνικά") # infers Greek
#> [1] "ΕΛΛΗΝΙΚΆ"
str_to_title("the cat sat on the mat")
#> [1] "The Cat Sat On The Mat"
str_to_sentence("the cat sat on the mat")
#> [1] "The cat sat on the mat"
Para reemplazar substrings según coincidencias de patrones, str_replace() cambia la primera aparición del patrón y str_replace_all() cambia todas las apariciones.
Para reemplazar substrings según índices de caracteres, existe una forma de asignación de str_sub().
s <- "abcde"
str_sub(s, 3, 4) <- "yz"
s
#> [1] "abyze"
str_dup crea duplicados y str_unique los elimina.
De forma predeterminada, str_dup no tiene separador, pero se puede especificar uno.
str_dup("xyz", 4, sep = ", ")
#> [1] "xyz, xyz, xyz, xyz"
str_unique es una extensión de unique().
Ambas eliminan entradas duplicadas de un vector, pero la función de stringr también puede manejar la distinción entre mayúsculas y minúsculas y varias coincidencias específicas de la configuración regional.
inp <- c("some", "strings", "Some", "Strings")
str_unique(inp)
#> [1] "some" "strings" "Some" "Strings"
str_unique(inp, ignore_case = TRUE)
#> [1] "some" "strings"
La biblioteca stringr se basa en la biblioteca stringi, que contiene funciones de más bajo nivel.
Si tienes necesidades específicas que no se hayan tratado antes, entonces: