Una stringa è un pezzo di testo racchiuso tra virgolette. Qualsiasi versione di R attualmente supportata codifica le stringhe in UTF-8, quindi è possibile gestire la maggior parte delle lingue del mondo.
mystring <- "some text"
mystring
#> [1] "some text"
typeof(mystring)
#> [1] "character"
Purtroppo, la terminologia può risultare confusa per chi programma e ha familiarità con altri linguaggi.
Anche se il type è character, R non fa alcuna distinzione tra una singola lettera (chiamata char in diversi altri linguaggi, ma non in R) e una stringa lunga.
Entrambe sono un singolo elemento e possono essere racchiuse tra virgolette singole ' ' o doppie " " in modo intercambiabile.
La guida di stile consiglia di usare le virgolette doppie, tranne quando vuoi usare le virgolette doppie all'interno della stringa senza fare escape.
str2 <- 'String with "quotes"' # convenience format
str2
#> [1] "String with \"quotes\"" # standard format
Un character vector è quindi un vettore di stringhe, in cui ogni stringa è un singolo 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
Nell'esempio precedente, length(s[1]) equivale a length("some"): il numero di elementi del vettore, non la lunghezza della stringa.
Manipolare una singola stringa è ovviamente possibile, come con nchar() nell'esempio precedente, ma richiede funzioni specifiche che vedremo più avanti.
Quasi tutto è possibile con l'R di base, ma molti programmatori trovano il supporto per la manipolazione delle stringhe piuttosto limitato e confusionario.
Fortunatamente, esistono i pacchetti tidyverse, molto più intuitivi, flessibili e coerenti al loro interno.
Esiste ancora molto codice legacy che usa funzioni per le stringhe in vecchio stile. Questo include la maggior parte delle soluzioni della community su Exercism.
Inoltre, per compiti piccoli può essere utile usare le funzioni integrate invece di importare una grande libreria. I manutentori del track R tendono a seguire questo approccio quando scrivono soluzioni di esempio per validare gli esercizi.
Perciò vale comunque la pena conoscere un po' i vecchi approcci.
ncharRestituisce il numero di caratteri in una stringa.
nchar("string")
#> [1] 6
nchar("Hrōðgār") # a person in Beowulf, written in Old English
#> [1] 7
L'argomento (complicato!) di cosa significhi «carattere» esula dallo scopo di questa introduzione. Basti notare un paio di punti negli esempi precedenti:
\0 (che aggiungerebbe 1 alla lunghezza).paste e paste0
Combina un numero arbitrario di stringhe in un'unica stringa.
Facoltativamente, si può specificare un separatore per paste: il valore predefinito è uno spazio.
paste0(v) is equivalent to paste(v, sep = "").
paste("bits", "of", "a", "string")
#> [1] "bits of a string"
paste0("bits", "of", "a", "string")
#> [1] "bitsofastring"
sprintfPer un controllo più preciso sull'assemblaggio delle stringhe, R riprende la funzione sprintf dal C (e da diversi linguaggi successivi: Wikipedia ne elenca circa 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"
trimwsGli spazi bianchi all'inizio e/o alla fine si possono rimuovere con trimws():
s <- " messy string "
trimws(s)
#> [1] "messy string"
Esiste un parametro which = "left" (o "right") per evitare di rimuovere gli spazi da entrambe le estremità.
substrOpera su una singola stringa e restituisce una sottostringa compresa tra due limiti (inclusi).
substr("Exercism", 5, 7)
#> [1] "cis"
strsplitDivide una stringa in una lista di R, in base a una stringa separatore. Il separatore è obbligatorio (non ha un valore predefinito), ma può essere una stringa vuota.
strsplit("R, Python, Julia", ", ")
[[1]]
#> [1] "R" "Python" "Julia"
strsplit("Exercism", "")
[[1]]
#> [1] "E" "x" "e" "r" "c" "i" "s" "m"
Le liste saranno trattate in un Concept a parte.
Se non hai ancora raggiunto quella parte del programma, per ora sappi solo che la funzione unlist() convertirà (in questo caso) una lista in un vettore.
unlist(strsplit("Exercism", ""))
#> [1] "E" "x" "e" "r" "c" "i" "s" "m"
Per essere generosi, potremmo dire che le funzioni per le stringhe in vecchio stile non sono il meglio che R abbia da offrire (esistono opinioni meno generose).
Per migliorare la situazione, la libreria stringr è in sviluppo dal 2009 ed è ormai una parte fondamentale della raccolta Tidyverse.
Importala nel tuo namespace con library(stringr) o library(tidyverse).
Alcune funzionalità chiave includono:
str_ e cercano di rendere chiaro lo scopo.Come tutti i pacchetti Tidyverse, stringr ha una buona documentazione, di solito scritta dall'autore o dagli autori del pacchetto.
L'uso dei pipe |> per collegare le funzioni sarà trattato più in dettaglio in altre parti del programma.
Per ora, è utile sapere che:
L'esempio seguente illustra la sintassi. Le singole funzioni saranno trattate più avanti.
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 i code point (simile a nchars).
Diverse altre funzioni manipolano gli spazi bianchi, tra cui str_trim() e str_squish().
Spesso è un'operazione di pulizia fondamentale all'inizio di qualsiasi progetto di data science.
# 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 funzione str_sub(string, start, end) restituirà la sottostringa da start a end (inclusi), mentre str_sub_all() può operare su più stringhe.
C'è molta flessibilità.
start e end hanno come valori predefiniti il primo e l'ultimo carattere, rispettivamente.
Possono essere vettori di indici.
In netto contrasto con l'indicizzazione dei vettori, i valori negativi contano a partire dalla fine della stringa, in stile 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 un vettore di caratteri in un'unica stringa.
L'argomento collapse viene inserito tra un elemento e l'altro e ha come valore predefinito "".
c("R", "Julia", "Python") |> str_flatten()
#> [1] "RJuliaPython"
c("R", "Julia", "Python") |> str_flatten(collapse = " - ")
#> [1] "R - Julia - Python"
str_c converte più vettori di caratteri in un unico vettore di caratteri, con il riciclo degli elementi quando necessario.
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 porta in R una semplice interpolazione di stringhe.
Le espressioni all'interno delle parentesi graffe { } vengono interpretate e la loro rappresentazione testuale viene sostituita al loro posto.
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 molto comune di R è trasformare dati disordinati in un formato coerente per l'analisi. Per aiutare in questo, ci sono diversi modi per dividere il testo in sottostringhe. La maggior parte va oltre lo scopo di questa introduzione.
str_split_1 è la più semplice: converte una singola stringa in un vettore di parti, suddivise in base a un pattern specificato (non c'è un pattern predefinito).
s <- "R Julia Python"
str_split_1(s, " ")
#> [1] "R" "Julia" "Python"
Alcuni linguaggi (per lo più europei) distinguono tra lettere MAIUSCOLE e minuscole.
Esiste un insieme di funzioni di stringr per convertire le une nelle altre, in modi adatti alla locale:
str_to_lower()str_to_upper()str_to_title() : la prima lettera di ogni parola in maiuscolostr_to_sentence() : la prima lettera della frase in maiuscolostr_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"
Per la sostituzione di sottostringhe basata sulla corrispondenza di un pattern, str_replace() modifica la prima occorrenza del pattern, str_replace_all() le modifica tutte.
Per la sostituzione di sottostringhe basata sull'indicizzazione dei caratteri, esiste una forma di assegnazione di str_sub().
s <- "abcde"
str_sub(s, 3, 4) <- "yz"
s
#> [1] "abyze"
In questo esercizio elaborerai delle righe di log.
Ogni riga di log è una stringa formattata così: "[<LEVEL>]: <MESSAGE>".
Esistono tre diversi livelli di log:
INFOWARNINGERRORHai tre attività, ognuna delle quali riceve una riga di log e ti chiede di fare qualcosa con essa.
Sei libero di usare sia le funzioni legacy di base R sia la libreria stringr: entrambe possono portare a soluzioni brevi e valide.
Implementa la funzione message in modo che restituisca il messaggio di una riga di log:
message("[ERROR]: Invalid operation")
#> "Invalid operation"
Eventuali spazi bianchi all'inizio o alla fine vanno rimossi:
message("[WARNING]: Disk almost full\r\n")
#> "Disk almost full"
Implementa la funzione log_level in modo che restituisca il livello di log di una riga di log, che va restituito in minuscolo:
log_level("[ERROR]: Invalid operation")
#> "error"
Implementa la funzione reformat che riformatta la riga di log, mettendo prima il messaggio e poi il livello di log tra parentesi tonde:
reformat("[INFO]: Operation completed")
#> "Operation completed (info)"
Iscriviti a Exercism per imparare e padroneggiare R con 21 concetti111 esercizi e il mentoring di persone reali, tutto gratis.