Una cadena de caracteres es un fragmento de texto entre comillas. Cualquier versión de R con soporte en la actualidad codifica los strings en UTF-8, así que se pueden admitir la mayoría de los idiomas del mundo.
mystring <- "some text"
mystring
#> [1] "some text"
typeof(mystring)
#> [1] "character"
Por desgracia, la terminología puede resultar confusa para quienes programan y conocen otros lenguajes.
Aunque el type sea character, R no distingue entre una sola letra (a la que en otros lenguajes se llama char, pero no en R) y un string largo.
Ambos son un único elemento y pueden ir entre comillas simples ' ' o dobles " " indistintamente.
La guía de estilo recomienda usar comillas dobles, salvo cuando quieras 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, por tanto, un vector de strings, donde cada string es un único 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 concreto es, obviamente, posible, como con nchar() en el ejemplo anterior, pero requiere funciones específicas que veremos más adelante.
En el R base casi todo es posible, 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 para strings del estilo antiguo. Entre ellos se incluyen 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 ejemplares para validar los ejercicios.
Por lo tanto, sigue mereciendo la pena conocer un poco los métodos antiguos.
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» se escapa del alcance de este documento. Basta con fijarse en un par de detalles de los ejemplos anteriores:
\0 (lo que sumaría 1 a la longitud).paste y paste0
Combina un número arbitrario de strings en un único string.
De forma opcional, se puede indicar 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 un control más preciso del ensamblado de strings, R copia la función sprintf de C (y de varios lenguajes posteriores: la 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 iniciales o finales se pueden eliminar con trimws():
s <- " messy string "
trimws(s)
#> [1] "messy string"
Hay un parámetro which = "left" (o «right») para evitar recortar ambos extremos.
substrOpera sobre un único string y devuelve una subcadena entre dos límites (ambos incluidos).
substr("Exercism", 5, 7)
#> [1] "cis"
strsplitDivide un string en una lista de R, a partir de 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 tratan 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() convertirá (en este caso) una lista en un vector.
unlist(strsplit("Exercism", ""))
#> [1] "E" "x" "e" "r" "c" "i" "s" "m"
Siendo benévolos, podríamos decir que las funciones para strings del estilo antiguo no son lo mejor que R tiene que ofrecer (opiniones menos benévolas también existen).
Para mejorar la situación, la biblioteca stringr está en desarrollo desde 2009 y hoy es una pieza clave de la colección Tidyverse.
Impórtala en tu espacio de nombres con library(stringr) o library(tidyverse).
Algunas de sus funcionalidades clave son:
str_ y tratan de dejar claro para qué sirven.Como todos los paquetes de Tidyverse, stringr tiene buena documentación, normalmente escrita por sus autores.
El uso de los pipes |> para conectar funciones se tratará con más detalle en otras partes del temario.
Por ahora, es útil saber lo siguiente:
El ejemplo siguiente ilustra la sintaxis. Las funciones concretas se comentará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 (parecido a nchars).
Otras funciones manipulan los espacios en blanco, como str_trim() y str_squish().
A menudo es una tarea de limpieza esencial al principio 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 la subcadena desde start hasta end (ambos incluidos), mientras que str_sub_all() puede operar sobre varios strings.
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 lo que ocurre (y se agradece) con la indexación de vectores, 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_flatten convierte un vector de caracteres en un único 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 único vector de caracteres, reciclando cuando es 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 aporta a R una interpolación de strings sencilla.
Las expresiones que hay dentro de llaves { } se interpretan y se sustituye su representación como texto.
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
Un uso muy habitual de R es dar forma a datos desordenados para dejarlos en un formato coherente que permita analizarlos. Para ayudarte con ello, hay varias formas de dividir texto en subcadenas. La mayoría quedan fuera de lo que tratamos aquí.
str_split_1 es la más sencilla: convierte un único string en un vector de fragmentos, dividiendo según un patrón que se especifica (no hay patrón predeterminado).
s <- "R Julia Python"
str_split_1(s, " ")
#> [1] "R" "Julia" "Python"
Algunos idiomas (principalmente europeos) distinguen entre letras MAYÚSCULAS y minúsculas.
Hay un conjunto de funciones de stringr para convertir unas en otras, de forma adecuada a cada configuración regional:
str_to_lower()str_to_upper()str_to_title() : pone en mayúscula la primera letra de cada palabrastr_to_sentence() : pone en mayúscula la primera letra de la frasestr_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 sustituir subcadenas según la coincidencia de un patrón, str_replace() cambia la primera aparición del patrón y str_replace_all() cambia todas las apariciones.
Para sustituir subcadenas según el índice de los caracteres, existe una forma de asignación de str_sub().
s <- "abcde"
str_sub(s, 3, 4) <- "yz"
s
#> [1] "abyze"
En este ejercicio vas a procesar líneas de log.
Cada línea de log es un string con este formato: "[<LEVEL>]: <MESSAGE>".
Hay tres niveles de log diferentes:
INFOWARNINGERRORTienes tres tareas y cada una recibe una línea de log y te pide que hagas algo con ella.
Puedes usar tanto las funciones heredadas de R base como la biblioteca stringr; ambas permiten llegar a soluciones breves y viables.
Implementa la función message para que devuelva el mensaje de una línea de log:
message("[ERROR]: Invalid operation")
#> "Invalid operation"
Hay que eliminar los espacios en blanco tanto al principio como al final:
message("[WARNING]: Disk almost full\r\n")
#> "Disk almost full"
Implementa la función log_level para que devuelva el nivel de log de una línea de log, que debe devolverse en minúsculas:
log_level("[ERROR]: Invalid operation")
#> "error"
Implementa la función reformat, que reformatea la línea de log colocando primero el mensaje y después el nivel de log entre paréntesis:
reformat("[INFO]: Operation completed")
#> "Operation completed (info)"
Regístrate en Exercism para aprender y dominar R con 21 conceptos111 ejercicios y mentoría humana real, todo gratis.