13.2 Základní operace
Nejdříve se podíváme na základní operace s řetězci: na to, jak řetězce spojovat, třídit, replikovat, nahrazovat, srovnávat a zjišťovat jejich délku. Ve zbytku kapitoly se pak budeme věnovat pokročilejší práci s řetězci pomocí regulárních výrazů.
13.2.1 Zjištění délky řetězce
Často potřebujeme zjistit délku jednotlivých řetězců. To nemůžeme udělat pomocí funkce length()
protože ta nevrací délku řetězce, ale délku vektoru řetězců. Nebude to fungovat ani v případě jediného řetězce, protože i to je vektor o délce 1. (Pamatujte, že R nemá skalár: to, co vypadá jako jeden řetězec, je ve skutečnosti vektor řetězců o délce 1.)
Ke zjištění délky řetězce slouží funkce str_length()
, která vrací vektor délek jednotlivých řetězců ve vektoru:
## [1] 1
## [1] 4
## [1] 5
## [1] 1 2 3 NA
Pozor: Technicky vzato vrací funkce str_length()
počet tzv. “code points”. Ty většinou odpovídají jednotlivým znakům, ne však vždy. Např. znak á
může být v paměti počítače reprezentován jako jeden znak nebo dva znaky (a
a akcent). Ve druhém případě vrátí funkce str_length()
délku 2. V takovém případě je bezpečnější počítat počet znaků pomocí funkce str_count()
, viz dále. Příklad najdete v dokumentaci funkce. Pokud jsou však anglické i české znaky zadané obvyklým způsobem, pak bude funkce str_length()
vracet počet znaků v jednotlivých řetězcích.
13.2.2 Spojení řetězců
Ke spojení více řetězců do jednoho slouží funkce str_c(..., sep = "", collapse = NULL)
. Funkce bere libovolný počet řetězců, vypustí z nich prázdné vektory řetězců a NULL
(ale ne prázdné řetězce ""
) a zbylé řetězce spojí do jednoho řetězce. Funkce str_c()
implicitně odděluje jednotlivé řetězce prázdným řetězcem, tj. spojí jednotlivé řetězce těsně za sebe. Oddělovací řetězec je možné nastavit pomocí pojmenovaného parametru sep
. (Všimněte si, že prázdný řetězec ""
funkce nevypustila.)
## [1] "Jednoubudemmožnádál!"
## [1] "Jednou budem možná dál!"
## [1] "Jednou--budem-možná-dál!"
Někdy potřebujeme spojit vektory řetězců. Funkce str_c()
spojí odpovídající prvky jednotlivých vektorů (s obvyklou recyklací kratších vektorů, při které funkce vypíše varování) a vrátí vektor (rozumnější použití uvidíte dále):
## Warning in stri_c(..., sep = sep, collapse = collapse, ignore_null = TRUE):
## longer object length is not a multiple of shorter object length
## [1] "a1" "b2" "c3" "d1"
Pokud navíc chceme výsledný vektor spojit do jednoho řetězce, můžeme použít parametr collapse
, kterým se nastavuje řetězec oddělující jednotlivé dílčí vektory (funguje i prázdný řetězec ""
):
## Warning in stri_c(..., sep = sep, collapse = collapse, ignore_null = TRUE):
## longer object length is not a multiple of shorter object length
## [1] "a1-b2-c3-d1"
## Warning in stri_c(..., sep = sep, collapse = collapse, ignore_null = TRUE):
## longer object length is not a multiple of shorter object length
## [1] "a1b2c3d1"
Celkove funguje funkce str_c()
takto: sve parametry chape jako vektory retezcu. Tyto vektory sestavi do matice, kde kazdy vstupni vektor tvori jeden sloupec teto matice (pritom prodlouzi kratsi vektory recyklaci jeho prvku). Pak vlozi mezi jednotlive sloupce retezec sep
a spoji kazdy radek do jednoho retezce, takze vysledkem je jeden vektor retezcu. Pokud je navic zadan retezec collapse
(tj. neni NULL
), funkce vlozi tento retezec mezi jednotlive prvky tohoto vektoru a spoji je do jednoho retezce. Tabulka 13.2 ukazuje, co udělá výraz str_c(s1, s2, sep = "-")
.
s1 |
(sep) | s2 |
výsledek |
---|---|---|---|
a | - | 1 | a-1 |
b | - | 2 | b-2 |
c | - | 3 | c-3 |
d | - | 1 | d-1 |
Pokud má kterýkoli řetězec ve spojovaných vektorech hodnotu NA
, pak je výsledné spojení také NA
:
## [1] "a1" "b2" NA
## [1] NA
Některé zajímavé příklady použití funkce str_c()
jsme vybrali z dokumentace funkce:
## [1] "Letter: a" "Letter: b" "Letter: c" "Letter: d" "Letter: e" "Letter: f"
## [7] "Letter: g" "Letter: h" "Letter: i" "Letter: j" "Letter: k" "Letter: l"
## [13] "Letter: m" "Letter: n" "Letter: o" "Letter: p" "Letter: q" "Letter: r"
## [19] "Letter: s" "Letter: t" "Letter: u" "Letter: v" "Letter: w" "Letter: x"
## [25] "Letter: y" "Letter: z"
## [1] "a comes before b" "b comes before c" "c comes before d" "d comes before e"
## [5] "e comes before f" "f comes before g" "g comes before h" "h comes before i"
## [9] "i comes before j" "j comes before k" "k comes before l" "l comes before m"
## [13] "m comes before n" "n comes before o" "o comes before p" "p comes before q"
## [17] "q comes before r" "r comes before s" "s comes before t" "t comes before u"
## [21] "u comes before v" "v comes before w" "w comes before x" "x comes before y"
## [25] "y comes before z"
## [1] "a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z"
13.2.3 Doplnění hodnot do řetězců
Někdy potřebujeme spojit několik řetězců tak, že na vybraná místa do textu “vlepíme” hodnoty z vybraných proměnných – např. když chceme sestavit výpis z účtu:
cislo_uctu <- 854397
zustatek <- 12365.30
str_c("Na účtu číslo ", cislo_uctu, " je aktuální zůstatek ",
format(zustatek, big.mark = ".", decimal.mark = ",", nsmall = 2),
" Kč.")
## [1] "Na účtu číslo 854397 je aktuální zůstatek 12.365,30 Kč."
Využít ke “vlepení” hodnot do řetězce funkci str_c()
, jak to ukazuje výše uvedený příklad, je možné, ale výsledek není právě přehledný. Místo toho můžeme použít speciální funkci glue()
z balíku glue:
library(glue)
hezky_zustatek <- format(zustatek, big.mark = '.',
decimal.mark = ',', nsmall = 2)
glue("Na účtu číslo {cislo_uctu} je aktualni zustatek {hezky_zustatek} Kč.")
## Na účtu číslo 854397 je aktualni zustatek 12.365,30 Kč.
Funkce glue()
vezme jeden nebo více řetězců, slepí je dohromady a na místa ve složených závorkách vloží hodnoty proměnných z aktuálního prostředí R, přesněji výsledek výpočtu, takže předchozí kód bychom mohli napsat i takto:
glue("Na účtu číslo {cislo_uctu} je aktualni zustatek ",
"{format(zustatek, big.mark = '.', decimal.mark = ',', nsmall = 2)} Kč.")
## Na účtu číslo 854397 je aktualni zustatek 12.365,30 Kč.
Hodnoty vložených proměnných můžeme zadat přímo jako parametry funkce glue()
:
glue("Na účtu číslo {cislo_uctu} je aktualni zustatek {zustatek} Kč.",
cislo_uctu = 24683, zustatek = 123)
## Na účtu číslo 24683 je aktualni zustatek 123 Kč.
Funkce glue()
má několik zajímavých vlastností: zahazuje počáteční a koncová bílá místa (mezery apod.) včetně prvního a posledního zalomení řádku, ostatní zalomení a mezery však respektuje:
## Toto je jakýsi text.
## A zde pokračuje...
##
## Toto je jakýsi text.
## A zde pokračuje...
Zalomení řádků je možné zabránit pomocí (zdvojeného) lomítka na jeho konci:
## Zde nějaký text začíná, a zde pokračuje.
Pokud z nějakého důvodu potřebujeme v textu použít složené závorky, máme dvě možnosti: buď je zdvojit, nebo pomocí parametrů .open
a .close
nastavit jiný počátek a konec nahrazované oblasti na jiný znak:
## Zde je {jméno}.
glue("Jméno výherce soutěže je {\\bf <<name>>}.", .open = "<<", .close =">>",
name = "Joe") # vhodné např. při exportu do LaTeXu
## Jméno výherce soutěže je {\bf Joe}.
Balík stringr nabízí podobnou funkcionalitu ve funkcích str_glue()
a str_interp()
. Funkce str_glue()
je vpodstatě jen wrapper nad funkcí glue()
a používá se stejně:
## Jmenuji se Jana a příští rok mi bude 41 let.
Naproti tomu funkce str_interp()
má poněkud jiné použití. V jejím případě musí mít nahrazovaný text buď podobu ${}
, kde ve složených závorkách je nějaký výraz, nebo $[]{}
, kde v hranatých závorkách je formát a v složených výraz. Formát určuje typicky formátování čísel – např. .2f
znamená, že se vytisknou dvě desetinná místa (detaily formátu viz nápověda k funkci sprintf()
). Pokud chceme zadat vkládané hodnoty přímo v této funkci, je třeba je zabalit do seznamu.
## [1] "Na účtu číslo 854397 je aktualni zustatek 12365.3 Kč."
## [1] "Na účtu číslo 854397 je aktualni zustatek 12365.30 Kč."
str_interp("Na účtu číslo $[d]{cislo_uctu} je aktualni zustatek $[.2f]{zustatek} Kč.",
list(cislo_uctu = 51349, zustatek = 17))
## [1] "Na účtu číslo 51349 je aktualni zustatek 17.00 Kč."
13.2.4 Řazení řetězců
Pro setřídění řetězců většinou stačí základní funkce sort()
a order()
. Pro složitější případy, kdy je např. třeba třídit v cizím locale, nabízí balík stringr dvě funkce:
str_order(x, decreasing = FALSE, na_last = TRUE, locale = "en", numeric = FALSE, ...)
vrací celé číslo, které odpovídá pořadí daného řetězce ve vektorux
(podobně jako funkceorder()
)str_sort(x, decreasing = FALSE, na_last = TRUE, locale = "en", numeric = FALSE, ...)
setřídí vektor řetězcůx
Přitom x
je vektor řetězců, který má být setříděn. decreasing
je logická hodnota (implicitní hodnota je FALSE
; pak třídí od nejnižšího k nejvyššímu; TRUE
třídí od nejvyššího k nejnižšímu). na_last
je logická hodnota (implicitní hodnota je TRUE
, při které funkce umístí hodnoty NA
na konec vektoru; FALSE
je umístí na začátek na začátek vektoru; NA
je vyhodí). locale
označuje v jakém locale se má třídit (implicitně v systémovém). Pokud je logická hodnota numeric
nastavena na TRUE
, pak číslice řadí jako čísla, ne jako řetězce; implicitní hodnota je FALSE
. ...
označují další parametry přidané do stri_opts_collator
.
## [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
## [26] 26
## [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s"
## [20] "t" "u" "v" "w" "x" "y" "z"
13.2.5 Výběr a náhrada pomocí indexů
Někdy je třeba z řetězce vybrat jeho část. Pokud známe pozici prvního a posledního znaku, který chceme vybrat, můžeme použít funkce str_sub(string, start = 1L, end = -1L)
, kde string
je řetězec, ze kterého vybíráme, start
je pozice znaku začátku výběru a end
je pozice konce výběru (včetně). Implicitní hodnota start
je 1 (tj. od začátku vektoru), implicitní hodnota end
je \(-1\) (tj. do konce vektoru). Pozice znaků mohou být zadány i jako záporná čísla – ta se počítají od konce vektoru, takže např. \(-1\) je poslední znak vektoru.
## [1] "Katastrofa na Marsu."
## [1] "Katastrofa na Marsu."
## [1] "Katastrofa na Marsu."
## [1] "Sol 6"
Funkce str_sub()
recykluje všechny své parametry. Pokud chceme např. vybrat stejné pozice z každého vektoru v řetězci:
## [1] "Katastrofa na Marsu." "Nová naděje."
## [1] "Katastrofa na Marsu." "Nová naděje."
Stejně tak je však možné recyklovat i řetězec a vybrat z něj naráz dva pod-řetězce:
## [1] "Katastrofa" "Marsu"
Pokud je řetěz kratší než výběr znaků, vrátí funkce str_sub()
tolik znaků, kolik může (někdy i prázdný řetězec):
## [1] "su."
## [1] ""
Funkci str_sub()
je možné použít i k náhradě části řetězce:
## [1] "Sol 6: Katastrofa na rudé planetě."
13.2.6 Replikace řetězců
Někdy je potřeba nějaký řetězec “zmnožit”. K tomu slouží funkce str_dup(string, times)
, který vezme vektor string
, zopakuje jej times
-krát a výsledek spojí. To se hodí např. při načítání mnoha textových sloupců pomocí balíku readr. Při tom je někdy užitečné říct funkci read_csv()
, že všechny sloupce tabulky mají typ character
. K tomu slouží řetězec mnoha “c”:
## [1] "cccccccccccccccccccccccccccc"
Funkce str_dup()
také recykluje všechny své parametry:
## [1] "a" "bb" "ccc"
13.2.7 Odstranění okrajových mezer
Někdy dostaneme řetězec, který začíná nebo končí “bílými znaky” (mezerami, tabelátory, novými řádky “\n
” apod.). Tato situace vznikne např. tehdy, když řetězec vznikl rozdělením delšího řetězce na části. Tyto bílé znaky je často vhodné odstranit. K tomu slouží funkce str_trim(string, side)
, kde string
je řetězec a side
označuje stranu, ze které se mají bílé znaky odstranit:
## [1] "Ahoj," "lidi, " "jak " "se" "máte?"
## [1] "Ahoj," " lidi," "jak" "se" " máte?"
## [1] "Ahoj," "lidi," "jak" "se" "máte?"
## [1] "Ahoj," "lidi," "jak" "se" "máte?"
Funkce str_squish(string)
funguje podobně, ale odstraní navíc i všechny přebytečné prázdné znaky – na začátku řetězce string
, na jeho konci i opakované znaky uvnitř:
## [1] "Toto je koktavý text."
13.2.8 Zarovnání a ořež řetězců na stejnou délku a do odstavce
Někdy je užitečné zarovnat řetězce na stejnou délku přidáním bílých (nebo jiných) znaků. K tomu slouží funkce str_pad(string, width, side, pad = " ")
, kde string
je vektor zarovnávaných řetězců, width
je minimální délka výsledného řetězce, side
je strana, na kterou se mají výplňové znaky přidat (implicitně je to left
) a pad
je výplňový řetězec (implicitně mezera).
## [1] " Ahoj" " lidi"
## [1] "--Ahoj---" "--lidi---"
Delší řetězce funkce nemění:
## [1] " Ahoj" "malé zelené bytosti z Viltvodlu VI"
V některých případech potřebujeme delší řetězec zkrátit na určitou délku tak, že se jeho část vynechá. K tomu slouží funkce str_trunc(string, width, side = c("right", "left", "center"), ellipsis = "...")
, která zkrátí řetězec string
na délku width
znaků. Přitom přebytečnou část textu na straně side
vynechá a nahradí znaky ellipsis
:
## [1] "Toto je přehnaně ..."
## [1] "...oho mnoho neříká."
## [1] "Toto je p... neříká."
Zarovnat řetězec do odstavce umožňuje funkce str_wrap(string, width = 80, indent = 0, exdent = 0)
, kde strings
je zarovnávaný řetězec, width
je cílová šířka sloupce (implicitně 80 znaků), indent
je odsazení prvního řádku a exdent
je odsazení následujících řádků (oboje implicitně 0 znaků):
s1 <- "Na počátku bylo Slovo, to Slovo bylo u Boha, to Slovo byl Bůh. To bylo na počátku u Boha. Všechno povstalo skrze ně a bez něho nepovstalo nic, co jest. V něm byl život a život byl světlo lidí. To světlo ve tmě svítí a tma je nepohltila."
cat(str_wrap(s1, 60))
## Na počátku bylo Slovo, to Slovo bylo u Boha, to Slovo byl
## Bůh. To bylo na počátku u Boha. Všechno povstalo skrze ně
## a bez něho nepovstalo nic, co jest. V něm byl život a život
## byl světlo lidí. To světlo ve tmě svítí a tma je nepohltila.
13.2.9 Konverze malých a velkých písmen
Ke konverzi malých písmen na velká slouží funkce str_to_upper(string, locale = "en")
, ke konverzi na malá písmena funkce str_to_lower(string, locale = "en")
, kde string
je převáděný řetězec. Parametr locale
umožňuje zadat popis jazykových pravidel pro převod znaků. Parametr je nepovinný a pokud není zadán, použije se aktuální locale počítače.
## [1] "nějaký malý textík..."
## [1] "NĚJAKÝ MALÝ TEXTÍK..."
13.2.10 Nahrazení chybějících hodnot řetězcem
Někdy máme vektor řetězců, ve kterém některé hodnoty chybí, tj. mají hodnotu NA
, a my potřebujeme tyto hodnoty nahradit nějakým textem. K tomu slouží funkce str_replace_na(string, replacement = "NA")
, kde string
je vektor řetězců a replacement
je řetězec, který má v řetězci string
nahradit chybějící hodnoty. Pokud chceme např. nahradit chybějící hodnoty slovem “neznámé”, můžeme to udělat takto:
## [1] "nahoře" "dole" "neznámá" "vlevo"
13.2.11 Formátování čísel
Někdy potřebujeme vytisknout čísla v “pěkném formátu”. To znamená, že musíme převést dané číslo na zformátovaný řetězec, který dané číslo prezentuje v požadovaném tvaru. K tomu slouží funkce format()
ze základního balíku base. Funkce format()
je generická a umí formátovat mnoho různých objektů. Pro čísla má následující parametry:
format(x, trim = FALSE, digits = NULL, nsmall = 0L,
justify = c("left", "right", "centre", "none"),
width = NULL, na.encode = TRUE, scientific = NA,
big.mark = "", big.interval = 3L,
small.mark = "", small.interval = 5L,
decimal.mark = getOption("OutDec"),
zero.print = NULL, drop0trailing = FALSE, ...)
kde x
je numerický vektor. Další užitečné parametry jsou zejména nsmall
(minimální počet desetinných míst), big.mark
a decimal.mark
(znak oddělující tisíce a desetinná místa), scientific
(pokud je TRUE
, pak vypisuje čísla ve vědecké notaci), width
(minimimální počet znaků) a justify
(zarovnání). Další parametry jsou popsané v dokumentaci.
## [1] 123456.3
## [1] "123.456,30"
## [1] "1.234563e+05"
## [1] " 123456.3"