Uma string, ou cadeia de caracteres, é um trecho de texto entre aspas.
mystring <- "some text"
mystring
#> [1] "some text"
typeof(mystring)
#> [1] "character"
Infelizmente, a terminologia pode confundir quem já programa em 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 no R) e uma string longa.
Ambos são um único item e podem ficar entre aspas simples ' ' ou duplas " ", indistintamente.
O guia de estilo recomenda usar aspas duplas, exceto quando você quer usar aspas duplas dentro da string sem escapá-las.
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 com nchar() no exemplo acima, mas exige funções específicas, que serão discutidas abaixo.
Como vimos acima, alguns caracteres de pontuação precisam ser "escapados" com uma barra invertida \ antes deles.
A lista não vai surpreender a maioria dos programadores experientes, já que esse assunto é bem padronizado entre as linguagens.
Além das aspas (como mostrado acima), a lista inclui quebras de linha \n, tabulações \t, a barra invertida \\ e símbolos Unicode que começam com \U ou \u.
Para evitar usar muitos escapes, é possível definir strings cruas dentro de r"( )":
r"(raw "string")"
#> [1] "raw \"string\""
Para strings cruas que contêm parênteses ( ), existem muitas outras opções de sintaxe.
Qualquer versão do R com suporte atual codifica strings em UTF-8, então a maioria das línguas do mundo pode ser atendida.
"आधुनिक मानक हिन्दी"
#> [1] "आधुनिक मानक हिन्दी"
Além disso, muitas funções do R levam em conta a locale e tentam seguir as convenções locais para ordenação de strings, conversão para maiúsculas/minúsculas, datas e horas, etc.
Este programa de estudos vai mostrar exemplos principalmente para o inglês dos EUA: tanto porque esse é um padrão comum, quanto porque os autores do programa de estudos moram nos EUA.
Localidades são um assunto complexo, então procure a documentação para a sua situação.
Quase tudo é possível no R base, mas muitos programadores acham o suporte à manipulação de strings bastante limitado e confuso.
Felizmente, existem pacotes do tidyverse que são bem mais intuitivos, flexíveis e coerentes entre si.
Ainda existe muito código legado usando funções de string no estilo antigo. Isso inclui a maioria das soluções da comunidade no Exercism.
Além disso, para tarefas pequenas pode ser útil usar funções nativas em vez de importar uma biblioteca grande. Quem mantém a trilha de R costuma adotar essa abordagem ao escrever soluções exemplares para validar os exercícios no nosso repositório do GitHub.
Por isso, ainda vale a pena conhecer um pouco das abordagens antigas.
As funções abaixo são apresentadas na forma mais simples, mas a maioria também tem argumentos opcionais. Consulte a documentação para mais detalhes.
ncharRetorna o número de caracteres em uma string.
nchar("string")
#> [1] 6
nchar("Hrōðgār") # a person in Beowulf, written in Old English
#> [1] 7
O assunto (complicado!) do que "caractere" significa está além do escopo deste texto. Repare só em dois pontos nos exemplos acima:
\0 (o que acrescentaria 1 ao comprimento).Cuidado com o que você passa para nchar.
Os resultados ainda podem ser imprevisíveis para valores que não são character, embora isso tenha melhorado nas versões recentes do R.
grepProcura um padrão em um vetor de strings e retorna os índices que deram correspondência.
grep("Jav", c("Java", "Python", "Javascript"))
#> [1] 1 3
paste e paste0
Combina um número qualquer de strings em uma única string.
Opcionalmente, é possível especificar um separador para paste: o padrão é 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 ter mais controle sobre a montagem de strings, o R copia a função sprintf do C (e de várias linguagens posteriores: a Wikipédia 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"
trimwsEspaç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 evitar remover as duas pontas.
substrAtua sobre uma única string e retorna a substring entre dois limites (inclusive).
substr("Exercism", 5, 7)
#> [1] "cis"
strsplitDivide uma string em uma lista do R, com base em uma string separadora. O separador é obrigatório (não tem padrão), 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"
Listas serão abordadas em um conceito separado.
Se você ainda não chegou a essa parte do programa de estudos, saiba por enquanto que a função unlist() vai (neste caso) converter uma lista em um vetor.
unlist(strsplit("Exercism", ""))
#> [1] "E" "x" "e" "r" "c" "i" "s" "m"
regexpr e regexpr
Abreviatura de "expressão regular", essas funções procuram ocorrências de um padrão em uma string e retornam uma lista de dados (potencialmente) úteis. Elas são mencionadas apenas por completude: existem opções melhores!
regexpr retorna apenas a primeira ocorrência; gregexpr retorna todas as ocorrências ("g" de busca "global").
Como os nomes sugerem, o padrão pode ser uma regex, que será abordada em um conceito posterior.
Por que essas funções de string antigas parecem comandos do shell do Unix?
Embora o R tenha sido criado em 1993, ele foi projetado para ser em grande parte compatível com a linguagem S.
A linguagem S foi criada nos Bell Labs e apareceu pela primeira vez em 1976. Os Bell Labs também foram responsáveis pelo Unix (a partir de 1969) e pela linguagem C (1972).
Que equipe, vinda de uma era muito mais antiga! Só podemos supor que eles conversavam entre si e trocavam ideias.
Sendo generosos, poderíamos dizer que as funções de string no estilo antigo não são o melhor que o R tem a oferecer (visões menos generosas também existem).
Para melhorar a situação, a biblioteca stringr está em desenvolvimento desde 2009 e hoje é parte essencial da coleção Tidyverse.
Importe a biblioteca para o seu namespace com library(stringr) ou library(tidyverse).
Alguns recursos importantes:
str_ e tentam deixar o propósito claro.Como todos os pacotes do Tidyverse, o stringr tem uma boa documentação, geralmente escrita por quem criou o pacote.
Há dezenas de funções disponíveis no stringr, e muitas vezes elas têm uma variedade de argumentos opcionais.
Isso pode ser um pouco assustador no começo, então a documentação é sua amiga.
Pense no que você quer colocar (uma única string? um vetor? algo mais complexo?) e no que quer obter.
Provavelmente existe um jeito fácil de fazer o que você quer, se você encontrar a função certa e os argumentos certos.
O uso de pipes |> para conectar funções será discutido com mais detalhes em outras partes do programa de estudos.
Por enquanto, é útil saber que:
O exemplo abaixo ilustra a sintaxe. As funções individuais serão discutidas 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"
A 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().
Isso costuma ser 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) retorna a substring de start até end (inclusive), enquanto a str_sub_all() pode operar sobre várias strings.
Há bastante flexibilidade.
start e end assumem, por padrão, o primeiro e o último caractere, respectivamente.
Eles podem ser vetores de índices.
Em contraste bem-vindo com a indexação de vetores, valores negativos contam a partir do fim da string, no 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_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"
A str_flatten converte um vetor de caracteres em uma única string.
O argumento collapse é inserido entre cada elemento e tem "" como padrão.
c("R", "Julia", "Python") |> str_flatten()
#> [1] "RJuliaPython"
c("R", "Julia", "Python") |> str_flatten(collapse = " - ")
#> [1] "R - Julia - Python"
A str_c converte vários vetores de caracteres em um único vetor de caracteres, 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"
A str_glue traz a interpolação de strings simples para o R.
As expressões dentro de chaves { } são interpretadas e a representação em texto é substituída.
Se várias strings de expressão forem fornecidas, elas também serão unidas como em str_flatten.
As strings também podem, opcionalmente, ter os espaços em branco do início e do fim removidos.
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
Embora a str_glue seja flexível (e bem complicada), há uma variedade ainda maior de possibilidades na biblioteca glue, que está por baixo.
Um uso muito comum do R é arrumar dados bagunçados em um formato consistente para análise. Para ajudar nisso, existem várias formas de dividir texto em substrings.
A str_split_1 é a mais simples: converte uma única string em um vetor de pedaços, divididos em algum padrão especificado (não existe padrão).
s <- "R Julia Python"
str_split_1(s, " ")
#> [1] "R" "Julia" "Python"
A str_split_i recebe um vetor de caracteres e um índice n e retorna um vetor com a n-ésima 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,"
A str_split recebe um vetor de caracteres e retorna uma lista de vetores.
Há um conceito de listas no nosso programa de estudos que explica essa saída.
str_split(s2, " ")
[[1]]
#> [1] "R" "Julia" "Python"
[[2]]
#> [1] "C" "Kotlin," "F#"
Há também a str_split_fixed, que retorna uma matriz.
Matrizes serão abordadas em um conceito posterior.
Para comparar a string inteira, a str_equal() pode usar várias definições de "igualdade".
Da forma mais simples, o padrão diferencia maiúsculas de minúsculas, mas isso pode ser mudado.
Localidades e o Unicode criam muitas outras possibilidades.
str_equal("Odin", "odin")
#> [1] FALSE
str_equal("Odin", "odin", ignore_case = TRUE)
#> [1] TRUE
Existem muitas outras funções, que serão discutidas com mais detalhes no conceito de expressões regulares.
Algumas linguagens (principalmente europeias) diferenciam letras MAIÚSCULAS e minúsculas.
Existe um conjunto de funções do stringr para converter entre essas formas, de maneiras adequadas à localidade:
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 em correspondência de padrões, a str_replace() altera a primeira ocorrência do padrão e a str_replace_all() altera todas as ocorrências.
Para substituir substrings com base na indexação de caracteres, existe uma forma de atribuição da str_sub().
s <- "abcde"
str_sub(s, 3, 4) <- "yz"
s
#> [1] "abyze"
A str_dup cria duplicatas e a str_unique remove duplicatas.
Por padrão, a str_dup não tem separador, mas é possível especificar um.
str_dup("xyz", 4, sep = ", ")
#> [1] "xyz, xyz, xyz, xyz"
A str_unique é uma extensão da unique().
As duas removem entradas duplicadas de um vetor, mas a função do stringr também consegue lidar com diferença entre maiúsculas e minúsculas e com vários tipos de correspondência específicos de cada localidade.
inp <- c("some", "strings", "Some", "Strings")
str_unique(inp)
#> [1] "some" "strings" "Some" "Strings"
str_unique(inp, ignore_case = TRUE)
#> [1] "some" "strings"
A biblioteca stringr é baseada na biblioteca stringi, de funções de nível mais baixo.
Se você tiver necessidades específicas que ainda não foram abordadas acima, então: