Kurzusok
/
R
R
/
Tanterv
/
Stringek
St

Stringek ebben a kurzusban: R

2 feladat

A(z) Stringek fogalomról

Háttér

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.

Escape-elés

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.

Területi beállítások

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.

Stringkezelő függvények

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.

Base R

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.

nchar

Egy 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:

  • Bár belsőleg C-ben vannak megvalósítva, az R stringjei nem \0-termináltak (ami 1-gyel növelné a hosszt).
  • A több bájtos Unicode-karaktereket úgy kezeli, ahogy várnád/remélnéd. A „Hrōðgār” 7 karakterből áll (ezeket „rúnáknak” vagy „kódpontoknak” is nevezik), tároláshoz viszont 10 bájt kell.

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.

grep

Egy 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"
sprintf

A 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"
trimws

A 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.

substr

Egyetlen stringen működik, és visszaadja a két (befoglaló) határ közötti részstringet.

substr("Exercism", 5, 7)
#> [1] "cis"
strsplit

Egy 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.

Advanced

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.

Tidyverse

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:

  • Minden függvénynév str_ előtaggal kezdődik, és igyekszik világosan kifejezni a célját.
  • Az argumentumok sorrendje igyekszik önmagában konzisztens lenni, a bemeneti adat az első argumentum.
  • A bemenet terjedhet egyetlen stringtől összetett adatszerkezetekig. A függvények igyekeznek alkalmazkodni, és a lehető legértelmesebbet tenni.

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.

Kitérő: Rövid bevezető a pipe-okba

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:

  • A pipe bal oldalán álló eredmény lesz a jobb oldali függvény első argumentuma (a „jobb oldali” itt figyelmen kívül hagyja az opcionális sortöréseket).
  • A fennmaradó argumentumok a függvényhíváson belül adhatók meg.
  • R-ben a pipe-nak mindig egy függvényhívásra kell irányulnia, nem csupán egy névre, ezért a zárójelek mindig kötelezők (ez eltér néhány más nyelvtől).

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"
Hosszúságok kezelése

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"
Részstringek kiválasztása

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"
Stringek összefűzése

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.

Stringek felbontása

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.

Stringek egyeztetése

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.

Stringek átalakítása

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 lesz
  • str_to_sentence() : a mondat első betűje nagybetűs lesz
str_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"
Egyebek

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"
Advanced

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:

  1. Nézd meg a stringr dokumentációját, amely több lehetőséget is lefed, mint amennyit még ebben a hosszú fogalmi dokumentumban is említhetünk.
  2. Nézd meg a stringi dokumentációját, amely még rengeteg funkciót ír le.
Szerkesztés GitHubon A hivatkozás új ablakban vagy lapon nyílik meg

Tanuld meg a(z) Stringek fogalmat

A gyakorlás zárolva

Oldj fel még 1 feladatot, hogy gyakorolhasd a(z) Stringek fogalmat