14 Caracteres
14.1 Introducción
Hasta ahora, ha usado un montón de cadenas de caracteres sin aprender mucho sobre los detalles. Ahora es el momento de sumergirse en ellas, aprender qué hace que las cadenas de caracteres funcionen y dominar algunas de las poderosas herramientas de manipulación de caracteres que tiene a su disposición.
Comenzaremos con los detalles de la creación de cadenas y vectores de caracteres. Luego se sumergirá en la creación de cadenas a partir de datos, luego lo contrario; extraer cadenas de datos. Luego hablaremos de las herramientas que funcionan con letras individuales. El capítulo finaliza con funciones que funcionan con letras individuales y una breve discusión sobre dónde podrían equivocarse sus expectativas del inglés al trabajar con otros idiomas.
Seguiremos trabajando con cadenas en el próximo capítulo, donde aprenderá más sobre el poder de las expresiones regulares.
14.1.1 Requisitos previos
En este capítulo, usaremos funciones del paquete stringr, que forma parte del núcleo tidyverse. También usaremos los datos de babynames ya que proporciona algunas cadenas divertidas para manipular.
Puede saber rápidamente cuándo está usando una función stringr porque todas las funciones stringr comienzan con str_
. Esto es particularmente útil si usa RStudio porque escribir str_
activará el autocompletado, lo que le permitirá refrescar su memoria de las funciones disponibles.
14.2 Creando una cadena de caracteres
Hemos creado cadenas de pasada anteriormente en el libro, pero no discutimos los detalles. En primer lugar, puede crear una cadena usando comillas simples ('
) o comillas dobles ("
). No hay diferencia en el comportamiento entre los dos, así que en aras de la coherencia, la guía de estilo de tidyverse recomienda usar "
, a menos que la cadena contiene múltiples "
.
string1 <- "Esta es una cadena de caracteres"
string2 <- 'Si quiero incluir una "comilla" dentro de una cadena, uso comillas simples'
Si olvida cerrar una comilla, verá +
, el indicador de continuación:
> "Esta es una cadena sin comillas de cierre
+
+
+ AYUDA ESTOY ATRAPADO EN UNA CADENA
Si esto le sucede y no sabe qué comilla cerrar, presione Escape para cancelar y vuelva a intentarlo.
14.2.1 Escapadas
Para incluir una comilla simple o doble literal en una cadena, puede usar \
para “escaparla”:
double_quote <- "\"" # o '"'
single_quote <- '\'' # o "'"
Entonces, si desea incluir una barra invertida literal en su cadena, deberá escapar: "\\"
:
backslash <- "\\"
Tenga en cuenta que la representación impresa de una cadena no es la misma que la cadena misma porque la representación impresa muestra los escapes (en otras palabras, cuando imprime una cadena, puede copiar y pegar la salida para recrear esa cadena). Para ver el contenido sin procesar de la cadena, use str_view()
1:
14.2.2 Cadenas de caracteres sin procesar
Crear una cadena con múltiples comillas o barras invertidas se vuelve confuso rápidamente. Para ilustrar el problema, creemos una cadena que contenga el contenido del bloque de código donde definimos las variables double_quote
y single_quote
:
tricky <- "double_quote <- \"\\\"\" # o '\"'
single_quote <- '\\'' # o \"'\""
str_view(tricky)
#> [1] │ double_quote <- "\"" # o '"'
#> │ single_quote <- '\'' # o "'"
¡Eso es un montón de barras invertidas! (Esto a veces se llama [síndrome del palillo inclinado] (https://en.wikipedia.org/wiki/Leaning_toothpick_syndrome).) Para eliminar el escape, puede usar una cadena de caracteres sin procesar2:
tricky <- r"(double_quote <- "\"" # or '"'
single_quote <- '\'' # or "'")"
str_view(tricky)
#> [1] │ double_quote <- "\"" # or '"'
#> │ single_quote <- '\'' # or "'"
Una cadena sin procesar generalmente comienza con r"(
y termina con )"
. Pero si su cadena contiene )"
, puede usar r"[]"
o r"{}"
, y si eso aún no es suficiente, puede insertar cualquier número de guiones para hacer los pares de apertura y cierre único, por ejemplo, r"--()--"
, r"---()---"
, etc. Las cadenas sin procesar son lo suficientemente flexibles para manejar cualquier texto.
14.2.3 Otros caracteres especiales
Además de \"
, \'
y \\
, hay otros caracteres especiales que pueden ser útiles. Los más comunes son \n
, una nueva línea y \t
, tabulador. A veces también verá cadenas que contienen escapes Unicode que comienzan con \u
o \U
. Esta es una forma de escribir caracteres no ingleses que funcionan en todos los sistemas. Puede ver la lista completa de otros caracteres especiales en ?Quote
.
Tenga en cuenta que str_view()
usa llaves para las pestañas para que sean más fáciles de detectar 3. Uno de los desafíos de trabajar con texto es que hay una variedad de formas en que los espacios en blanco pueden terminar en el texto, por lo que este fondo lo ayuda a reconocer que algo extraño está sucediendo.
14.2.4 Ejercicios
-
Cree cadenas que contengan los siguientes valores:
Él dijo: "¡Eso es increíble!"
\a\b\c\d
\\\\\\
-
Cree la cadena en su sesión R e imprímala. ¿Qué sucede con el especial “\u00a0”? ¿Cómo lo muestra
str_view()
? ¿Puedes googlear un poco para averiguar qué es este carácter especial?x <- "Esto\u00a0es\u00a0complicado"
14.3 Crear muchas cadenas de caracteres a partir de datos
Ahora que ha aprendido los conceptos básicos para crear una o dos cadenas “a mano”, entraremos en los detalles de la creación de cadenas a partir de otras cadenas. Esto lo ayudará a resolver el problema común en el que tiene un texto que escribió que desea combinar con cadenas de un data frame. Por ejemplo, puede combinar “Hola” con una variable name
para crear un saludo. Le mostraremos cómo hacer esto con str_c()
y str_glue()
y cómo puede usarlos con mutate()
. Naturalmente, eso plantea la pregunta de qué funciones de stringr podría usar con summarize()
, por lo que terminaremos esta sección con una discusión de str_flatten()
, que es una función de resumen para cadenas.
14.3.1 str_c()
str_c()
toma cualquier número de vectores como argumentos y devuelve un vector de caracteres:
str_c()
es muy similar a la base paste0()
, pero está diseñado para usarse con mutate()
obedeciendo las reglas habituales de tidyverse para reciclar y propagar valores faltantes:
Si desea que los valores faltantes se muestren de otra manera, use coalesce()
para reemplazarlos. Dependiendo de lo que quieras, puedes usarlo dentro o fuera de str_c()
:
df |>
mutate(
greeting1 = str_c("Hi ", coalesce(name, "you"), "!"),
greeting2 = coalesce(str_c("Hi ", name, "!"), "Hi!")
)
#> # A tibble: 4 × 3
#> name greeting1 greeting2
#> <chr> <chr> <chr>
#> 1 Flora Hi Flora! Hi Flora!
#> 2 David Hi David! Hi David!
#> 3 Terra Hi Terra! Hi Terra!
#> 4 <NA> Hi you! Hi!
14.3.2 str_glue()
Si está mezclando muchas cadenas fijas y variables con str_c()
, notará que escribe muchas "
s, lo que dificulta ver el objetivo general del código. Un enfoque alternativo es proporcionado por el paquete glue a través de str_glue()
4. Le das una sola cadena que tiene una característica especial: cualquier cosa dentro de {}
se evaluará como que está fuera de las comillas:
Como puede ver, str_glue()
actualmente convierte los valores faltantes a la cadena "NA"
, desafortunadamente, lo que lo hace inconsistente con str_c()
.
También puede preguntarse qué sucede si necesita incluir un {
o }
regular en su cadena. Estás en el camino correcto si crees que necesitarás escapar de alguna manera. El truco es que el pegamento usa una técnica de escape ligeramente diferente; en lugar de anteponer un carácter especial como \
, se duplican los caracteres especiales:
14.3.3 str_flatten()
str_c()
y str_glue()
funciona bien con mutate()
porque su salida tiene la misma longitud que sus entradas. ¿Qué pasa si quieres una función que funcione bien con summarize()
, es decir, algo que siempre devuelva una sola cadena? Ese es el trabajo de str_flatten()
5: toma un vector de caracteres y combina cada elemento del vector en una sola cadena:
str_flatten(c("x", "y", "z"))
#> [1] "xyz"
str_flatten(c("x", "y", "z"), ", ")
#> [1] "x, y, z"
str_flatten(c("x", "y", "z"), ", ", last = ", and ")
#> [1] "x, y, and z"
Esto hace que funcione bien con summarize()
:
df <- tribble(
~ name, ~ fruit,
"Carmen", "banana",
"Carmen", "apple",
"Marvin", "nectarine",
"Terence", "cantaloupe",
"Terence", "papaya",
"Terence", "mandarin"
)
df |>
group_by(name) |>
summarize(fruits = str_flatten(fruit, ", "))
#> # A tibble: 3 × 2
#> name fruits
#> <chr> <chr>
#> 1 Carmen banana, apple
#> 2 Marvin nectarine
#> 3 Terence cantaloupe, papaya, mandarin
14.3.4 Ejercicios
-
Compare y contraste los resultados de
paste0()
constr_c()
para las siguientes entradas: ¿Cuál es la diferencia entre
paste()
ypaste0()
? ¿Cómo puedes recrear el equivalente depaste()
constr_c()
?-
Convierta las siguientes expresiones de
str_c()
astr_glue()
o viceversa:str_c("El precio de ", food, " es ", price)
str_glue("Yo tengo {age} años y vivo en {country}")
str_c("\\section{", title, "}")
14.4 Extraer datos de cadenas de caracteres
Es muy común que varias variables se amontonen en una sola cadena. En esta sección, aprenderá a utilizar cuatro funciones tidyr para extraerlas:
df |> separate_longer_delim(col, delim)
df |> separate_longer_position(col, width)
df |> separate_wider_delim(col, delim, names)
df |> separate_wider_position(col, widths)
Si miras de cerca, puedes ver que hay un patrón común aquí: separate_
, luego longer
o wider
, luego _
, luego por delim
o position
. Eso es porque estas cuatro funciones se componen de dos primitivas más simples: - Al igual que con pivot_longer()
y pivot_wider()
, las funciones _longer
hacen que el data frame de entrada sea más largo al crear nuevas filas y las funciones _wider
hacen que el data frame de entrada sea más ancho al generar nuevas columnas. - delim
divide una cadena con un delimitador como ", "
o " "
; position
se divide en anchos específicos, como c(3, 5, 2)
.
Volveremos al último miembro de esta familia, separate_wider_regex()
, en Capítulo 15. Es la más flexible de las funciones wider
, pero necesita saber algo acerca de las expresiones regulares antes de poder usarla.
Las siguientes dos secciones le darán la idea básica detrás de estas funciones separadas, primero separándolas en filas (que es un poco más simple) y luego separándolas en columnas. Terminaremos discutiendo las herramientas que le brindan las funciones wider
para diagnosticar problemas.
14.4.1 Separando en filas
Separar una cadena en filas tiende a ser más útil cuando el número de componentes varía de una fila a otra. El caso más común requiere que separate_longer_delim()
se divida en función de un delimitador:
df1 <- tibble(x = c("a,b,c", "d,e", "f"))
df1 |>
separate_longer_delim(x, delim = ",")
#> # A tibble: 6 × 1
#> x
#> <chr>
#> 1 a
#> 2 b
#> 3 c
#> 4 d
#> 5 e
#> 6 f
Es más raro ver separate_longer_position()
en la naturaleza, pero algunos conjuntos de datos más antiguos usan un formato muy compacto donde cada carácter se usa para registrar un valor:
df2 <- tibble(x = c("1211", "131", "21"))
df2 |>
separate_longer_position(x, width = 1)
#> # A tibble: 9 × 1
#> x
#> <chr>
#> 1 1
#> 2 2
#> 3 1
#> 4 1
#> 5 1
#> 6 3
#> # ℹ 3 more rows
14.4.2 Separando en columnas
Separar una cadena en columnas tiende a ser más útil cuando hay un número fijo de componentes en cada cadena y desea distribuirlos en columnas. Son un poco más complicados que sus equivalentes longer
porque necesitas nombrar las columnas. Por ejemplo, en el siguiente conjunto de datos, x
se compone de un código, un número de edición y un año, separados por "."
. Para usar separate_wider_delim()
, proporcionamos el delimitador y los nombres en dos argumentos:
df3 <- tibble(x = c("a10.1.2022", "b10.2.2011", "e15.1.2015"))
df3 |>
separate_wider_delim(
x,
delim = ".",
names = c("code", "edition", "year")
)
#> # A tibble: 3 × 3
#> code edition year
#> <chr> <chr> <chr>
#> 1 a10 1 2022
#> 2 b10 2 2011
#> 3 e15 1 2015
Si una pieza específica no es útil, puede usar un nombre NA
para omitirla de los resultados:
df3 |>
separate_wider_delim(
x,
delim = ".",
names = c("code", NA, "year")
)
#> # A tibble: 3 × 2
#> code year
#> <chr> <chr>
#> 1 a10 2022
#> 2 b10 2011
#> 3 e15 2015
separate_wider_position()
funciona un poco diferente porque normalmente desea especificar el ancho de cada columna. Entonces le das un vector entero con nombre, donde el nombre da el nombre de la nueva columna, y el valor es la cantidad de caracteres que ocupa. Puede omitir valores de la salida si no los nombra:
df4 <- tibble(x = c("202215TX", "202122LA", "202325CA"))
df4 |>
separate_wider_position(
x,
widths = c(year = 4, age = 2, state = 2)
)
#> # A tibble: 3 × 3
#> year age state
#> <chr> <chr> <chr>
#> 1 2022 15 TX
#> 2 2021 22 LA
#> 3 2023 25 CA
14.4.3 Diagnóstico de problemas de ensanchamiento
separate_wider_delim()
6 requiere un conjunto fijo y conocido de columnas. ¿Qué sucede si alguna de las filas no tiene el número esperado de piezas? Hay dos posibles problemas, muy pocas o demasiadas piezas, por lo que separate_wider_delim()
proporciona dos argumentos para ayudar: too_few
y too_many
. Primero veamos el caso too_few
con el siguiente conjunto de datos de muestra:
df <- tibble(x = c("1-1-1", "1-1-2", "1-3", "1-3-2", "1"))
df |>
separate_wider_delim(
x,
delim = "-",
names = c("x", "y", "z")
)
#> Error in `separate_wider_delim()`:
#> ! Expected 3 pieces in each element of `x`.
#> ! 2 values were too short.
#> ℹ Use `too_few = "debug"` to diagnose the problem.
#> ℹ Use `too_few = "align_start"/"align_end"` to silence this message.
Notará que recibimos un error, pero el error nos da algunas sugerencias sobre cómo puede proceder. Comencemos por depurar el problema:
debug <- df |>
separate_wider_delim(
x,
delim = "-",
names = c("x", "y", "z"),
too_few = "debug"
)
#> Warning: Debug mode activated: adding variables `x_ok`, `x_pieces`, and
#> `x_remainder`.
debug
#> # A tibble: 5 × 6
#> x y z x_ok x_pieces x_remainder
#> <chr> <chr> <chr> <lgl> <int> <chr>
#> 1 1-1-1 1 1 TRUE 3 ""
#> 2 1-1-2 1 2 TRUE 3 ""
#> 3 1-3 3 <NA> FALSE 2 ""
#> 4 1-3-2 3 2 TRUE 3 ""
#> 5 1 <NA> <NA> FALSE 1 ""
Cuando usa el modo de depuración, obtiene tres columnas adicionales agregadas a la salida: x_ok
, x_pieces
y x_remainder
(si separa una variable con un nombre diferente, obtendrá un prefijo diferente). Aquí, x_ok
te permite encontrar rápidamente las entradas que fallaron:
debug |> filter(!x_ok)
#> # A tibble: 2 × 6
#> x y z x_ok x_pieces x_remainder
#> <chr> <chr> <chr> <lgl> <int> <chr>
#> 1 1-3 3 <NA> FALSE 2 ""
#> 2 1 <NA> <NA> FALSE 1 ""
x_pieces
nos dice cuántas piezas se encontraron, en comparación con las 3 esperadas (la longitud de names
). x_remainder
no es útil cuando hay muy pocas piezas, pero lo veremos de nuevo en breve.
A veces, mirar esta información de depuración revelará un problema con su estrategia de delimitación o sugerirá que necesita hacer más preprocesamiento antes de separarse. En ese caso, solucione el problema aguas arriba y asegúrese de eliminar too_few = "debug"
para asegurarse de que los nuevos problemas se conviertan en errores.
En otros casos, es posible que desee completar las piezas que faltan con “NA” y seguir adelante. Ese es el trabajo de too_few = "align_start"
y too_few = "align_end"
que le permiten controlar dónde deben ir los NA
:
df |>
separate_wider_delim(
x,
delim = "-",
names = c("x", "y", "z"),
too_few = "align_start"
)
#> # A tibble: 5 × 3
#> x y z
#> <chr> <chr> <chr>
#> 1 1 1 1
#> 2 1 1 2
#> 3 1 3 <NA>
#> 4 1 3 2
#> 5 1 <NA> <NA>
Los mismos principios se aplican si tiene demasiadas piezas:
df <- tibble(x = c("1-1-1", "1-1-2", "1-3-5-6", "1-3-2", "1-3-5-7-9"))
df |>
separate_wider_delim(
x,
delim = "-",
names = c("x", "y", "z")
)
#> Error in `separate_wider_delim()`:
#> ! Expected 3 pieces in each element of `x`.
#> ! 2 values were too long.
#> ℹ Use `too_many = "debug"` to diagnose the problem.
#> ℹ Use `too_many = "drop"/"merge"` to silence this message.
Pero ahora, cuando depuramos el resultado, puedes ver el propósito de x_remainder
:
debug <- df |>
separate_wider_delim(
x,
delim = "-",
names = c("x", "y", "z"),
too_many = "debug"
)
#> Warning: Debug mode activated: adding variables `x_ok`, `x_pieces`, and
#> `x_remainder`.
debug |> filter(!x_ok)
#> # A tibble: 2 × 6
#> x y z x_ok x_pieces x_remainder
#> <chr> <chr> <chr> <lgl> <int> <chr>
#> 1 1-3-5-6 3 5 FALSE 4 -6
#> 2 1-3-5-7-9 3 5 FALSE 5 -7-9
Tiene un conjunto ligeramente diferente de opciones para manejar demasiadas piezas: puede “soltar” silenciosamente cualquier pieza adicional o “fusionarlas” todas en la columna final:
df |>
separate_wider_delim(
x,
delim = "-",
names = c("x", "y", "z"),
too_many = "drop"
)
#> # A tibble: 5 × 3
#> x y z
#> <chr> <chr> <chr>
#> 1 1 1 1
#> 2 1 1 2
#> 3 1 3 5
#> 4 1 3 2
#> 5 1 3 5
df |>
separate_wider_delim(
x,
delim = "-",
names = c("x", "y", "z"),
too_many = "merge"
)
#> # A tibble: 5 × 3
#> x y z
#> <chr> <chr> <chr>
#> 1 1 1 1
#> 2 1 1 2
#> 3 1 3 5-6
#> 4 1 3 2
#> 5 1 3 5-7-9
14.5 Letras
En esta sección, le presentaremos funciones que le permitirán trabajar con letras individuales dentro de una cadena. Aprenderá a encontrar la longitud de una cadena, extraer subcadenas y manejar cadenas largas en diagramas y tablas.
14.5.1 Longitud
str_length()
te dice el número de letras en la cadena:
str_length(c("a", "R for data science", NA))
#> [1] 1 18 NA
Podría usar esto con count()
para encontrar la distribución de las longitudes de los nombres de bebés de EE. UU. y luego con filter()
para ver los nombres más largos, que tienen 15 letras 7:
babynames |>
count(length = str_length(name), wt = n)
#> # A tibble: 14 × 2
#> length n
#> <int> <int>
#> 1 2 338150
#> 2 3 8589596
#> 3 4 48506739
#> 4 5 87011607
#> 5 6 90749404
#> 6 7 72120767
#> # ℹ 8 more rows
babynames |>
filter(str_length(name) == 15) |>
count(name, wt = n, sort = TRUE)
#> # A tibble: 34 × 2
#> name n
#> <chr> <int>
#> 1 Franciscojavier 123
#> 2 Christopherjohn 118
#> 3 Johnchristopher 118
#> 4 Christopherjame 108
#> 5 Christophermich 52
#> 6 Ryanchristopher 45
#> # ℹ 28 more rows
14.5.2 Subconjunto
Puedes extraer partes de una cadena usando str_sub(string, start, end)
, donde start
y end
son las posiciones donde la subcadena debe comenzar y terminar. Los argumentos start
y end
son inclusivos, por lo que la longitud de la cadena devuelta será end - start + 1
:
Puede usar valores negativos para contar hacia atrás desde el final de la cadena: -1 es el último carácter, -2 es el penúltimo carácter, etc.
str_sub(x, -3, -1)
#> [1] "ple" "ana" "ear"
Tenga en cuenta que str_sub()
no fallará si la cadena es demasiado corta: solo devolverá tanto como sea posible:
str_sub("a", 1, 5)
#> [1] "a"
Podríamos usar str_sub()
con mutate()
para encontrar la primera y última letra de cada nombre:
babynames |>
mutate(
first = str_sub(name, 1, 1),
last = str_sub(name, -1, -1)
)
#> # A tibble: 1,924,665 × 7
#> year sex name n prop first last
#> <dbl> <chr> <chr> <int> <dbl> <chr> <chr>
#> 1 1880 F Mary 7065 0.0724 M y
#> 2 1880 F Anna 2604 0.0267 A a
#> 3 1880 F Emma 2003 0.0205 E a
#> 4 1880 F Elizabeth 1939 0.0199 E h
#> 5 1880 F Minnie 1746 0.0179 M e
#> 6 1880 F Margaret 1578 0.0162 M t
#> # ℹ 1,924,659 more rows
14.5.3 Ejercicios
- ¿Cuando calculamos la distribución de la longitud de los nombres de los bebés, ¿por qué usamos
wt = n
? - Use
str_length()
ystr_sub()
para extraer la letra del medio de cada nombre de bebé. ¿Qué harás si la cadena tiene un número par de caracteres? - ¿Existen tendencias importantes en la longitud de los nombres de bebés a lo largo del tiempo? ¿Qué pasa con la popularidad de las primeras y últimas letras?
14.6 Texto no inglés
Hasta ahora, nos hemos centrado en el texto en inglés, con el que es particularmente fácil trabajar por dos razones. En primer lugar, el alfabeto inglés es relativamente simple: solo hay 26 letras. En segundo lugar (y quizás más importante), la infraestructura informática que usamos hoy en día fue diseñada predominantemente por angloparlantes. Desafortunadamente, no tenemos espacio para un tratamiento completo de los idiomas distintos del inglés. Aún así, queríamos llamar su atención sobre algunos de los mayores desafíos que podría encontrar: codificación, variaciones de letras y funciones dependientes de la configuración regional.
14.6.1 Codificación
Cuando se trabaja con texto que no está en inglés, el primer desafío suele ser la codificación. Para entender lo que está pasando, necesitamos sumergirnos en cómo las computadoras representan cadenas. En R, podemos llegar a la representación subyacente de una cadena usando charToRaw()
:
charToRaw("Hadley")
#> [1] 48 61 64 6c 65 79
Cada uno de estos seis números hexadecimales representa una letra: 48
es H, 61
es a, y así sucesivamente. La asignación de un número hexadecimal a un carácter se denomina codificación y, en este caso, la codificación se denomina ASCII. ASCII hace un gran trabajo al representar los caracteres ingleses porque es el código estándar estadounidense para el intercambio de información.
Las cosas no son tan fáciles para otros idiomas además del inglés. En los primeros días de la informática, existían muchos estándares en competencia para codificar caracteres no ingleses. Por ejemplo, había dos codificaciones diferentes para Europa: Latin1 (también conocido como ISO-8859-1) se usaba para los idiomas de Europa occidental, y Latin2 (también conocido como ISO-8859-2) se usaba para los idiomas de Europa Central. En Latin1, el byte b1
es “±”, pero en Latin2, ¡es “±”! Afortunadamente, hoy en día existe un estándar que se admite en casi todas partes: UTF-8. UTF-8 puede codificar casi todos los caracteres utilizados por los humanos en la actualidad y muchos símbolos adicionales como emojis.
readr usa UTF-8 en todas partes. Este es un buen valor predeterminado, pero fallará para los datos producidos por sistemas más antiguos que no usan UTF-8. Si esto sucede, sus cadenas se verán raras cuando las imprima. A veces, solo uno o dos caracteres pueden estar en mal estado; otras veces, obtendrás un completo galimatías. Por ejemplo, aquí hay dos CSV en línea con codificaciones inusuales 8:
Para leerlos correctamente, especifica la codificación a través del argumento locale
:
¿Cómo encuentras la codificación correcta? Si tiene suerte, se incluirá en algún lugar de la documentación de datos. Desafortunadamente, ese rara vez es el caso, por lo que readr proporciona guess_encoding()
para ayudarlo a resolverlo. No es infalible y funciona mejor cuando tiene mucho texto (a diferencia de aquí), pero es un lugar razonable para comenzar. Espere probar algunas codificaciones diferentes antes de encontrar la correcta.
Las codificaciones son un tema rico y complejo; solo hemos arañado la superficie aquí. Si desea obtener más información, le recomendamos leer la explicación detallada en http://kunststube.net/encoding/.
14.6.2 Variaciones de letras
Trabajar en idiomas con acentos plantea un desafío significativo al determinar la posición de las letras (por ejemplo, con str_length()
y str_sub()
), ya que las letras acentuadas pueden codificarse como un solo carácter individual (por ejemplo, ü) o como dos caracteres por combinar una letra sin acento (por ejemplo, u) con un signo diacrítico (por ejemplo, ¨). Por ejemplo, este código muestra dos formas de representar ü que parecen idénticas:
Pero ambas cadenas difieren en longitud y sus primeros caracteres son diferentes:
str_length(u)
#> [1] 1 2
str_sub(u, 1, 1)
#> [1] "ü" "u"
Finalmente, tenga en cuenta que una comparación de estas cadenas con ==
interpreta estas cadenas como diferentes, mientras que la práctica función str_equal()
en stringr reconoce que ambas tienen la misma apariencia:
u[[1]] == u[[2]]
#> [1] FALSE
str_equal(u[[1]], u[[2]])
#> [1] TRUE
14.6.3 Funciones dependientes de la configuración regional
Finalmente, hay un puñado de funciones stringr cuyo comportamiento depende de tu locale. Una configuración regional es similar a un idioma, pero incluye un especificador de región opcional para manejar las variaciones regionales dentro de un idioma. Una configuración regional se especifica mediante una abreviatura de idioma en minúsculas, seguida opcionalmente por un _
y un identificador de región en mayúsculas. Por ejemplo, “en” es inglés, “en_GB” es inglés británico y “en_US” es inglés americano. Si aún no conoce el código de su idioma, Wikipedia tiene una buena lista, y puede ver cuáles son compatibles con stringr mirando stringi::stri_locale_list()
.
Las funciones de cadena base R utilizan automáticamente la configuración regional establecida por su sistema operativo. Esto significa que las funciones base de cadena R hacen lo que espera para su idioma, pero su código podría funcionar de manera diferente si lo comparte con alguien que vive en un país diferente. Para evitar este problema, stringr utiliza por defecto las reglas en inglés utilizando la configuración regional “en” y requiere que especifique el argumento locale
para anularlo. Afortunadamente, hay dos conjuntos de funciones donde la configuración regional realmente importa: cambio de mayúsculas y minúsculas y clasificación.
Las reglas para cambiar entre mayúsculas y minúsculas difieren entre idiomas. Por ejemplo, el turco tiene dos i: con y sin punto. Como son dos letras distintas, se escriben en mayúsculas de manera diferente:
str_to_upper(c("i", "ı"))
#> [1] "I" "I"
str_to_upper(c("i", "ı"), locale = "tr")
#> [1] "İ" "I"
¡La clasificación de las cadenas depende del orden del alfabeto, y el orden del alfabeto no es el mismo en todos los idiomas 9! He aquí un ejemplo: en checo, “ch” es una letra compuesta que aparece después de la h
en el alfabeto.
Esto también surge al ordenar cadenas con dplyr::arrange()
, por lo que también tiene un argumento locale
.
14.7 Resumen
En este capítulo, aprendió algo sobre el poder del paquete stringr: cómo crear, combinar y extraer cadenas, y sobre algunos de los desafíos que puede enfrentar con cadenas que no están en inglés. Ahora es el momento de aprender una de las herramientas más importantes y poderosas para trabajar con cadenas: las expresiones regulares. Las expresiones regulares son un lenguaje muy conciso pero muy expresivo para describir patrones dentro de cadenas y son el tema del próximo capítulo.
O usa la función base R
writeLines()
.↩︎Disponible en R 4.0.0 y superior.↩︎
str_view()
también usa colores para llamar su atención sobre tabulaciones, espacios, coincidencias, etc. Los colores no aparecen actualmente en el libro, pero los notará cuando ejecute el código de forma interactiva.↩︎Si no está usando stringr, también puede acceder a él directamente con
glue::glue()
.↩︎El equivalente base de R es
paste()
usado con el argumentocollapse
.↩︎Los mismos principios se aplican a
separate_wider_position()
yseparate_wider_regex()
.↩︎Mirando estas entradas, supondríamos que los datos de babynames eliminan espacios o guiones y se truncan después de 15 letras.↩︎
Aquí estoy usando el
\x
especial para codificar datos binarios directamente en una cadena.↩︎Clasificar en idiomas que no tienen alfabeto, como el chino, es aún más complicado.↩︎