Uma string é um pedaço de texto entre aspas. Qualquer versão de R atualmente suportada codifica as strings em UTF-8, pelo que é possível suportar a maioria das línguas do mundo.
mystring <- "some text"
mystring
#> [1] "some text"
typeof(mystring)
#> [1] "character"
Infelizmente, esta terminologia pode ser confusa para programadores familiarizados com outras linguagens.
Apesar de o type ser character, o R não faz distinção entre uma única letra (chamada char em várias outras linguagens, mas não em R) e uma string longa.
Ambas são um único item e podem estar entre aspas simples ' ' ou duplas " ", indistintamente.
O guia de estilo recomenda usar aspas duplas, exceto quando queres usar aspas duplas dentro da string sem as escapar.
str2 <- 'String with "quotes"' # convenience format
str2
#> [1] "String with \"quotes\"" # standard format
Um character vector é, portanto, um vetor de strings, em que cada string é um ú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
No exemplo acima, length(s[1]) é equivalente a length("some"): o número de elementos do vetor, não o comprimento da string.
Manipular uma string individual é obviamente possível, como acontece com nchar() no exemplo acima, mas exige funções específicas, que serão abordadas a seguir.
No R base, quase tudo é possível, mas muitos programadores consideram o suporte para manipulação de strings bastante limitado e confuso.
Felizmente, existem pacotes do tidyverse que são muito mais intuitivos, flexíveis e coerentes.
Ainda existe muito código legado que usa funções de string ao estilo antigo. Isto inclui a maioria das soluções da comunidade no Exercism.
Além disso, em tarefas pequenas pode ser útil usar funções incorporadas em vez de importar uma biblioteca grande. Quem mantém o track de R no Exercism tende a seguir esta abordagem quando escreve soluções exemplares para validar os exercícios.
Por isso, ainda vale a pena conhecer algumas das abordagens antigas.
ncharDevolve o número de carateres numa string.
nchar("string")
#> [1] 6
nchar("Hrōðgār") # a person in Beowulf, written in Old English
#> [1] 7
O tema (complicado!) do que significa "caráter" está fora do âmbito desta introdução. Repara apenas em alguns pontos nos exemplos acima:
\0 (o que acrescentaria 1 ao comprimento).paste e paste0
Combina um número arbitrário de strings numa única string.
Opcionalmente, pode indicar-se um separador para paste: o valor predefinido é um espaço.
paste0(v) é equivalente a paste(v, sep = "").
paste("bits", "of", "a", "string")
#> [1] "bits of a string"
paste0("bits", "of", "a", "string")
#> [1] "bitsofastring"
sprintfPara um controlo mais fino sobre a construção de strings, o R copia a função sprintf do C (e de várias linguagens posteriores: a Wikipedia lista cerca de 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"
trimwsOs espaços em branco no início e/ou no fim podem ser removidos com trimws():
s <- " messy string "
trimws(s)
#> [1] "messy string"
Existe um parâmetro which = "left" (ou "right") para não remover os espaços das duas extremidades.
substrAtua sobre uma única string e devolve uma substring entre dois limites (inclusive).
substr("Exercism", 5, 7)
#> [1] "cis"
strsplitDivide uma string numa lista de R, com base numa string separadora. O separador é obrigatório (não tem valor predefinido), mas pode ser uma string vazia.
strsplit("R, Python, Julia", ", ")
[[1]]
#> [1] "R" "Python" "Julia"
strsplit("Exercism", "")
[[1]]
#> [1] "E" "x" "e" "r" "c" "i" "s" "m"
As listas serão abordadas num Conceito separado.
Se ainda não chegaste a essa parte do currículo, fica a saber, por agora, que a função unlist() vai (neste caso) converter uma lista num vetor.
unlist(strsplit("Exercism", ""))
#> [1] "E" "x" "e" "r" "c" "i" "s" "m"
Sendo generosos, podemos dizer que as funções de string ao estilo antigo não são o melhor que o R tem para oferecer (há opiniões menos generosas).
Para melhorar esta situação, a biblioteca stringr está em desenvolvimento desde 2009 e é agora uma parte fundamental da coleção Tidyverse.
Importa-a para o teu namespace com library(stringr) ou library(tidyverse).
Algumas características principais:
str_ e procuram deixar claro o seu propósito.Tal como todos os pacotes do Tidyverse, o stringr tem boa documentação, normalmente escrita por quem criou o pacote.
O uso de pipes |> para encadear funções será abordado com mais detalhe noutras partes do currículo.
Por agora, é útil saber que:
O exemplo abaixo ilustra a sintaxe. As funções individuais serão abordadas mais adiante.
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 conta pontos de código (semelhante a nchars).
Várias outras funções manipulam espaços em branco, incluindo str_trim() e str_squish().
Isto é, muitas vezes, uma tarefa de limpeza essencial no início de qualquer projeto de ciência de dados.
# 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"
A função str_sub(string, start, end) devolve a substring de start a end (inclusive), enquanto str_sub_all() pode atuar sobre várias strings.
Há muita flexibilidade.
start e end assumem por predefinição o primeiro e o último caráter, respetivamente.
Podem ser vetores de índices.
Em contraste bem-vindo com a indexação de vetores, os valores negativos contam a partir do fim da string, ao estilo do 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 converte um vetor de carateres numa única string.
O argumento collapse é inserido entre cada elemento e assume "" por predefinição.
c("R", "Julia", "Python") |> str_flatten()
#> [1] "RJuliaPython"
c("R", "Julia", "Python") |> str_flatten(collapse = " - ")
#> [1] "R - Julia - Python"
str_c converte vários vetores de carateres num único vetor de carateres, com reciclagem quando necessário.
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 traz a interpolação simples de strings ao R.
As expressões dentro de chavetas { } são interpretadas e substitui-se a representação textual.
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
Um uso muito comum do R é arrumar dados desorganizados num formato consistente para análise. Para ajudar nisto, há várias formas de dividir texto em substrings. A maioria está fora do âmbito atual.
str_split_1 é a mais simples: converte uma única string num vetor de partes, divididas por um padrão especificado (não há padrão predefinido).
s <- "R Julia Python"
str_split_1(s, " ")
#> [1] "R" "Julia" "Python"
Algumas linguagens (sobretudo europeias) distinguem entre letras MAIÚSCULAS e minúsculas.
Existe um conjunto de funções do stringr para converter umas nas outras, de formas adequadas a cada localização:
str_to_lower()str_to_upper()str_to_title() : primeira letra de cada palavra em maiúsculastr_to_sentence() : primeira letra da frase em maiú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 substituir substrings com base na correspondência de padrões, str_replace() altera a primeira ocorrência do padrão e str_replace_all() altera todas as ocorrências.
Para substituir substrings com base na indexação de carateres, existe uma forma de atribuição de str_sub().
s <- "abcde"
str_sub(s, 3, 4) <- "yz"
s
#> [1] "abyze"
Neste exercício vais processar linhas de log.
Cada linha de log é uma string com o seguinte formato: "[<LEVEL>]: <MESSAGE>".
Existem três níveis de log diferentes:
INFOWARNINGERRORTens três tarefas, cada uma recebe uma linha de log e pede-te para fazer algo com ela.
Podes usar à vontade tanto funções legacy do R base como a biblioteca stringr, e ambas permitem soluções curtas e viáveis.
Implementa a função message para devolver a mensagem de uma linha de log:
message("[ERROR]: Invalid operation")
#> "Invalid operation"
Qualquer espaço em branco no início ou no fim deve ser removido:
message("[WARNING]: Disk almost full\r\n")
#> "Disk almost full"
Implementa a função log_level para devolver o nível de log de uma linha de log, que deve ser devolvido em minúsculas:
log_level("[ERROR]: Invalid operation")
#> "error"
Implementa a função reformat que reformata a linha de log, colocando a mensagem primeiro e o nível de log a seguir, entre parênteses:
reformat("[INFO]: Operation completed")
#> "Operation completed (info)"
Inscreve-te no Exercism para aprenderes e dominares R com 21 conceitos111 exercícios, e mentoria humana real, tudo grátis.