A string egy idézőjelek közé zárt szövegrész.
mystring <- "some text"
mystring
#> [1] "some text"
typeof(mystring)
#> [1] "character"
Sajnos a terminológia zavaró lehet a más nyelveket ismerő programozók számára.
Bár a type értéke character, az R nem tesz különbséget egyetlen betű (amit több más nyelvben char-nak hívnak, az R-ben viszont nem) és egy hosszú string között.
Mindkettő egyetlen elem, és ugyanúgy állhat egyszeres ' ' vagy kettős " " idézőjelek között.
A stíluskalauz a kettős idézőjelek használatát javasolja, kivéve, ha kettős idézőjelet szeretnél a stringen belül használni anélkül, hogy escape-elnéd őket.
str2 <- 'String with "quotes"' # convenience format
str2
#> [1] "String with \"quotes\"" # standard format
A character vector tehát stringek vektora, ahol minden string egyetlen elem.
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
A fenti példában a length(s[1]) ugyanaz, mint a length("some"): a vektorelemek számát adja vissza, nem a string hosszát.
Egy-egy string manipulálása természetesen lehetséges, ahogy a fenti példában a nchar() is mutatja, ehhez viszont speciális függvények kellenek, amelyeket alább tárgyalunk.
Ahogy fentebb láttuk, néhány írásjelet „escape-elni” kell, azaz egy visszaperjelet \ kell eléjük tenni.
A lista a legtöbb tapasztalt programozót nem lepi meg, mivel ez a téma meglehetősen egységesen szabványosított a nyelvek között.
Az idézőjelek mellett (amint fentebb láttuk) a listán szerepelnek a sortörések \n, a tabulátorok \t, a visszaperjel \\ és a \U vagy \u karakterekkel kezdődő Unicode-szimbólumok.
Hogy elkerüljük a rengeteg escape-karaktert, nyers stringeket definiálhatunk az r"( )" jelöléssel:
r"(raw "string")"
#> [1] "raw \"string\""
A zárójelet ( ) tartalmazó nyers stringekhez sok más szintaktikai lehetőség létezik.
Az R minden jelenleg támogatott verziója UTF-8-ban kódolja a stringeket, így a világ nyelveinek többsége támogatható.
"आधुनिक मानक हिन्दी"
#> [1] "आधुनिक मानक हिन्दी"
Emellett számos R-függvény ismeri a locale fogalmát, és igyekszik követni a helyi szokásokat a stringek rendezésében, a kis- és nagybetűvé alakításában, a dátumokban és időpontokban stb.
Ez a tanterv főleg amerikai angol példákat mutat: egyrészt mert ez gyakori alapértelmezés, másrészt mert a tanterv szerzői épp az Egyesült Államokban élnek.
A területi beállítások összetett téma, ezért keress dokumentációt a saját helyzetedhez.
A base R-ben szinte minden lehetséges, de sok programozó elég korlátozottnak és zavarosnak találja a stringmanipuláció támogatását.
Szerencsére léteznek tidyverse-csomagok, amelyek sokkal intuitívabbak, rugalmasabbak és önmagukban konzisztensebbek.
Még mindig sok régi kód használ régi stílusú stringfüggvényeket. Ide tartozik az Exercism legtöbb közösségi megoldása is.
Emellett kis feladatoknál hasznos lehet a beépített függvények használata egy nagy könyvtár importálása helyett. Az R-kurzus karbantartói is ezt a megközelítést követik, amikor mintamegoldásokat írnak a feladatok ellenőrzéséhez a GitHub-tárolónkban.
Ezért érdemes még mindig elsajátítani valamennyit a régi megközelítésekből.
Az alábbi függvényeket a legegyszerűbb formájukban mutatjuk be, de a legtöbbjüknek opcionális argumentumai is vannak. A részletekért nézd meg a dokumentációt.
ncharEgy string karaktereinek számát adja vissza.
nchar("string")
#> [1] 6
nchar("Hrōðgār") # a person in Beowulf, written in Old English
#> [1] 7
Az, hogy mit jelent a „karakter”, (bonyolult!) téma, és túlmutat a jelen oldal keretein. Csupán jegyezz meg néhány dolgot a fenti példákból:
\0-termináltak (ami 1-gyel növelné a hosszt).Vigyázz, mit adsz át a nchar függvénynek.
A nem character típusú értékeknél az eredmény még mindig kiszámíthatatlan lehet, bár ez a közelmúltbeli R-verziókban javult.
grepEgy mintát keres stringek vektorában, és visszaadja az egyező elemek indexeit.
grep("Jav", c("Java", "Python", "Javascript"))
#> [1] 1 3
paste és paste0
Tetszőleges számú stringet fűz össze egyetlen stringgé.
A paste esetében opcionálisan megadható egy elválasztó: az alapértelmezett a szóköz.
A paste0(v) ugyanaz, mint a paste(v, sep = "").
paste("bits", "of", "a", "string")
#> [1] "bits of a string"
paste0("bits", "of", "a", "string")
#> [1] "bitsofastring"
sprintfA stringek összeállításának finomabb szabályozásához az R a C nyelvből vette át a sprintf függvényt (és számos későbbi nyelv is: a Wikipédia mintegy 30-at sorol fel).
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"
trimwsA vezető és/vagy záró whitespace eltávolítható a trimws() függvénnyel:
s <- " messy string "
trimws(s)
#> [1] "messy string"
Létezik egy which = "left" (vagy „right”) paraméter, amellyel elkerülhető mindkét vég levágása.
substrEgyetlen stringen működik, és visszaadja a két (befoglaló) határ közötti részstringet.
substr("Exercism", 5, 7)
#> [1] "cis"
strsplitEgy stringet bont fel R-listára egy elválasztó string alapján. Az elválasztó kötelező (nincs alapértéke), de lehet üres string is.
strsplit("R, Python, Julia", ", ")
[[1]]
#> [1] "R" "Python" "Julia"
strsplit("Exercism", "")
[[1]]
#> [1] "E" "x" "e" "r" "c" "i" "s" "m"
A listákat egy külön fogalom tárgyalja.
Ha még nem jutottál el a tantervnek ahhoz a részéhez, egyelőre elég annyit tudnod, hogy az unlist() függvény (ebben az esetben) listát alakít vektorrá.
unlist(strsplit("Exercism", ""))
#> [1] "E" "x" "e" "r" "c" "i" "s" "m"
regexpr és regexpr
A „regular expression” rövidítéseként ezek a függvények egy minta előfordulásait keresik egy stringben, és (esetleg) hasznos adatok listáját adják vissza. Csupán a teljesség kedvéért említjük őket: vannak jobb megoldások!
A regexpr csak az első előfordulást adja vissza, a gregexpr az összeset (a „g” a „global” keresést jelenti).
Ahogy a nevek is sugallják, a minta lehet regex, amelyet egy későbbi fogalom tárgyal majd.
Miért hasonlítanak ezek a régi stringfüggvények Unix parancsértelmező-parancsokra?
Bár az R 1993-ban született, nagy részben visszafelé kompatibilisnek tervezték az S nyelvvel.
Az S-t a Bell Labsnál tervezték, és 1976-ban jelent meg először. A Bell Labs felelt a Unixért (1969-től) és a C nyelvért (1972) is.
Igazi csapat volt az a sokkal korábbi korszakból! Csak feltételezni tudjuk, hogy beszéltek egymással és megosztották az ötleteiket.
Jóindulatúan fogalmazva azt mondhatjuk, hogy a régi stílusú stringfüggvények nem az R legjobbjei (a kevésbé jóindulatú vélemények is elérhetők).
A helyzet javítására a stringr könyvtár 2009 óta fejlődik, és mára a Tidyverse gyűjtemény kulcsfontosságú része.
Importáld a névtérbe a library(stringr) vagy a library(tidyverse) paranccsal.
Néhány fontos jellemzője:
str_ előtaggal kezdődik, és igyekszik világosan kifejezni a célját.Mint minden Tidyverse-csomagnak, a stringr-nek is jó dokumentációja van, amelyet jellemzően a csomag szerzője (szerzői) írt.
A stringr-ben tucatnyi függvény érhető el, és ezeknek gyakran számos opcionális argumentumuk van.
Ez elsőre kicsit nyomasztó lehet, szóval a dokumentáció lesz a barátod.
Gondold végig, mit szeretnél beírni (egy stringet? egy vektort? valami bonyolultabbat?), és mit szeretnél kivenni belőle.
Valószínűleg van egyszerű módja annak, amit szeretnél, ha megtalálod a megfelelő függvényt és a megfelelő argumentumokat.
A függvények összekapcsolására szolgáló |> pipe-ok használatát a tanterv más részei tárgyalják részletesebben.
Egyelőre elég annyit tudnod, hogy:
Az alábbi példa szemlélteti a szintaxist. Az egyes függvényeket később tárgyaljuk.
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 kódpontokat számol (hasonlóan a nchars-hoz).
Számos más függvény kezeli a whitespace-t, például a str_trim() és a str_squish().
Ez gyakran elengedhetetlen tisztítási feladat minden adattudományi projekt elején.
# 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 str_sub(string, start, end) függvény a start-tól end-ig (befoglalóan) tartó részstringet adja vissza, a str_sub_all() pedig több stringen is működhet.
Nagy a rugalmasság.
A start és az end alapértéke az első, illetve az utolsó karakter.
Indexek vektorai is lehetnek.
A vektorindexeléssel ellentétben (ami kifejezetten üdvözlendő) a negatív értékek a string végétől számolnak visszafelé, a Python stílusában.
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 egy karaktervektort alakít egyetlen stringgé.
A collapse argumentum minden elem közé bekerül, alapértéke pedig "".
c("R", "Julia", "Python") |> str_flatten()
#> [1] "RJuliaPython"
c("R", "Julia", "Python") |> str_flatten(collapse = " - ")
#> [1] "R - Julia - Python"
A str_c több karaktervektort alakít egyetlen karaktervektorrá, szükség szerinti újrahasznosítással.
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 egyszerű string-interpolációt hoz az R-be.
A kapcsos zárójelek { } közötti kifejezések kiértékelődnek, és a szöveges reprezentációjuk behelyettesítődik.
Ha több kifejezést adsz meg, azok is összefűződnek, akárcsak a str_flatten esetében.
A stringek vezető/záró whitespace-e opcionálisan levágható.
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
Bár a str_glue rugalmas (és meglehetősen bonyolult), még szélesebb lehetőségek rejlenek a mögötte álló glue könyvtárban.
Az R egyik nagyon gyakori felhasználása, hogy a rendetlen adatokat elemzésre alkalmas, egységes formába gyúrja. Ezt segítik a szöveg részstringekre bontásának különféle módjai.
A str_split_1 a legegyszerűbb: egyetlen stringet alakít darabok vektorává, egy megadott minta mentén felbontva (nincs alapértelmezett minta).
s <- "R Julia Python"
str_split_1(s, " ")
#> [1] "R" "Julia" "Python"
A str_split_i egy karaktervektort és egy n indexet vár, és minden bemeneti string n-edik részstringjéből álló vektort ad vissza.
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 egy karaktervektort vár, és vektorok listáját adja vissza.
A tantervünkben van egy listákról szóló fogalom, amely elmagyarázza a kimenetet.
str_split(s2, " ")
[[1]]
#> [1] "R" "Julia" "Python"
[[2]]
#> [1] "C" "Kotlin," "F#"
Létezik a str_split_fixed is, amely mátrixot ad vissza.
A mátrixokat egy későbbi fogalom tárgyalja.
A teljes string összehasonlításához a str_equal() az „egyenlőség” többféle meghatározását is használhatja.
A legegyszerűbb esetben az alapértelmezés kis- és nagybetűre érzékeny, de ez megváltoztatható.
A területi beállítások és a Unicode még számos lehetőséget teremt.
str_equal("Odin", "odin")
#> [1] FALSE
str_equal("Odin", "odin", ignore_case = TRUE)
#> [1] TRUE
Sok más függvény is létezik, amelyeket a reguláris kifejezések fogalma tárgyal részletesebben.
Egyes nyelvek (főleg az európaiak) megkülönböztetik a NAGYBETŰKET és a kisbetűket.
A stringr függvényei ezeket a helyi szokásoknak megfelelően alakítják át egymásba:
str_to_lower()str_to_upper()str_to_title() : minden szó első betűje nagybetűs leszstr_to_sentence() : a mondat első betűje nagybetűs leszstr_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"
Mintaegyezésen alapuló részstring-cseréhez a str_replace() a minta első előfordulását cseréli, a str_replace_all() pedig az összeset.
Karakterindexelésen alapuló részstring-cseréhez a str_sub() értékadó formája használható.
s <- "abcde"
str_sub(s, 3, 4) <- "yz"
s
#> [1] "abyze"
A str_dup másolatokat készít, a str_unique pedig eltávolítja az ismétlődéseket.
A str_dup alapértelmezésben nem használ elválasztót, de megadható neki egy.
str_dup("xyz", 4, sep = ", ")
#> [1] "xyz, xyz, xyz, xyz"
A str_unique a unique() kiterjesztése.
Mindkettő eltávolítja az ismétlődő elemeket egy vektorból, de a stringr függvénye a kis- és nagybetű-érzékenységet, valamint a különféle helyi beállításokhoz kötődő egyezéseket is kezelni tudja.
inp <- c("some", "strings", "Some", "Strings")
str_unique(inp)
#> [1] "some" "strings" "Some" "Strings"
str_unique(inp, ignore_case = TRUE)
#> [1] "some" "strings"
A stringr könyvtár a stringi könyvtárra épül, amely alacsonyabb szintű függvényeket kínál.
Ha olyan speciális igényed van, amelyet fentebb még nem tárgyaltunk, akkor: