Kurzusok
/
R
R
/
Tanterv
/
Reguláris kifejezések
Re

Reguláris kifejezések ebben a kurzusban: R

1 feladat

A(z) Reguláris kifejezések fogalomról

A reguláris kifejezések rendkívül sokoldalú eszközt kínálnak a stringek mintaillesztésére, egy erre a célra tervezett domain-specifikus nyelven (DSL) keresztül.

Advanced

Ahogy sok más programozási nyelv, az R sem próbál saját regexkönyvtárat megvalósítani. Ehelyett az ICU reguláris kifejezésmotorját használja. Az ICU hasonlít a népszerű PCRE2 könyvtárhoz, amelyet a legtöbb újabb nyelv használ, bár néhány határesetet másképp kezel.

A regex számos képessége be van építve a Base R-be, és régebbi kódokban láthatsz is példákat rá.

Új kód esetén erősen ajánlott a stringr könyvtár használata.

Ahogy a Strings fogalom is megjegyzi, a stringr dokumentációja jó, és rendszerint a csomag szerzője (szerzői) írja.

Note

Ez az R tanterv feltételezi, hogy már ismered a regexek alapvető szintaxisát. Kizárólag az R-specifikus jellemzőkre összpontosítunk.

Az alábbiakban néhány forrást találsz, amivel felfrissítheted a reguláris kifejezésekkel kapcsolatos ismereteidet.

A Strings fogalomban már tárgyalt függvények közül sok alapértelmezés szerint regexes keresésre készült.

A Strings fogalmat viszonylag egyszerűen tartottuk, csak stringliterálokra illesztettünk, de bármilyen regexminta használható helyette.

Formálisan egy regexet R-ben a regex() meghívásával hozunk létre. A kényelem kedvéért a stringr függvényei minden mintaként átadott stringet regexként kezelnek. Az alábbi példában az első str_replace_all() szintaktikai cukor a második változathoz:

input <- "Some input string"

# "\\s" matches any whitespace character
input |> str_replace_all("\\s", "_")
[1] "Some_input_string"

input |> str_replace_all(regex("\\s"), "_")
[1] "Some_input_string"

A puskalap hasznos útmutató: minden pattern argumentummal rendelkező függvény (pirossal szedve) elfogad regexet, és a 2. oldal összefoglalja a regex szintaxisát.

Vedd figyelembe, hogy a regex() függvény továbbra is fontos lehet, ha felül kell bírálnod az alapértelmezéseket, például a kis- és nagybetűk megkülönböztetését vagy a locale-t.

# default is case sensitive
"A Mixed Assortment" |> 
    str_replace_all(regex("[aeiou]", ignore_case = TRUE), "*")
#> [1] "* M*x*d *ss*rtm*nt"

Sok regexben szerepel backslash, például a fenti \s is. A szokásos R stringekben a \ karaktert meg kell duplázni, ezért lesz belőle "\\s".

A backslashek elszaporodhatnak és zavaróvá válhatnak, ezért bonyolult esetekben segíthet a raw stringek használata.

Alapértelmezés szerint a raw string definiálásának szintaxisa r"( )", de más határolójelek is megengedettek. Mivel a regex szintaxisában a kerek zárójelek ( ) és a szögletes zárójelek [ ] egyaránt gyakoriak (rögzítő csoportokra és opciócsoportokra), a kapcsos zárójelek { } jó választás lehet.

input |> str_replace_all(r"{\s\w}", "__")
#> [1] "Some__nput__tring"

Találatok felismerése

Íme néhány kérdés, és néhány függvény, amelyek segíthetnek megválaszolni őket.

Néhány példa a fruit vektort használja, amely 80 gyümölcsnevet tartalmaz, és a stringr-rel együtt jár gyakorlási célból.

Tartalmaz egy string találatot? str_detect(), vagy str_starts(), illetve str_ends(), hogy ne kelljen a ^ vagy $ horgonyt használnod.

# berries begining with b
fruit |> str_detect("^b.*berry") |> head(15)
#> [1] FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE FALSE FALSE  TRUE  TRUE FALSE FALSE FALSE FALSE

# alternative syntax
fruit |> str_starts("b.*berry") |> head(15)
#> [1] FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE FALSE FALSE  TRUE  TRUE FALSE FALSE FALSE FALSE

Csak a találatot tartalmazó stringeket szeretnéd visszakapni? A str_subset() függvénnyel megkapod a stringeket, a str_which() függvénnyel pedig az indexeket.

fruit |> str_subset("a...e")
[1] "apple"       "blackberry"  "mandarine"   "nectarine"   "pineapple"   "pomegranate" "raspberry"   "salal berry"
> fruit |> str_which("a...e")
[1]  1  7 48 51 62 64 70 73

Hány találat van az egyes stringekben? str_count()

# count vowels
fruit |> str_count("[aeiou]") |> head(10)
#> [1] 2 3 4 3 3 2 2 3 5 3

Hol van a találat? Interaktív használathoz a str_view(), általánosabban a str_locate() vagy a str_locate_all().

# str_view only shows matching elements, with match in < > delimiters
fruit |> str_view("a...e")
 [1] │ <apple>
 [7] │ bl<ackbe>rry
[48] │ mand<arine>
[51] │ nect<arine>
[62] │ pine<apple>
[64] │ pomegr<anate>
[70] │ r<aspbe>rry
[73] │ sal<al be>rry

# str_locate returns all elements
fruit |> str_locate("a...e") |> head(10)
      start end
 [1,]     1   5
 [2,]    NA  NA
 [3,]    NA  NA
 [4,]    NA  NA
 [5,]    NA  NA
 [6,]    NA  NA
 [7,]     3   7
 [8,]    NA  NA
 [9,]    NA  NA
[10,]    NA  NA

Rögzítések

Gyakran szeretnénk tudni, hogy mi illeszkedik. Ezt úgy érhetjük el, hogy rögzítő csoportokat teszünk zárójelbe a regexen belül.

Lehetőség van arra, hogy ugyanazon a regexen belül visszahivatkozz a rögzítésekre a \1, \2 stb. segítségével. Például ismétlődő betűpárok megkeresése:

fruit |> str_subset("(..)\\1")
[1] "banana"      "coconut"     "cucumber"    "jujube"      "papaya"      "salal berry"

Hasonló szintaxissal a rögzítések a helyettesítő stringekben is használhatók:

# double to triple
fruit |> 
  str_subset("(..)\\1") |> 
  str_replace("(..)\\1", "\\1\\1\\1")
[1] "bananana"      "cococonut"     "cucucumber"    "jujujube"      "papapaya"      "salalal berry"

A találatokat későbbi feldolgozáshoz a str_match() függvénnyel gyűjtheted össze, ha csak az első találatra vagy kíváncsi, vagy a str_match_all() függvénnyel, ha az összesre.

A rögzítő csoportok minden nyelvben hajlamosak bonyolult kimenetet adni. Az R megközelítése (amely ráadásul vektorizált, ami plusz kihívást jelent) az, hogy a str_match() egy mátrixot hoz létre: minden bemeneti stringhez egy sor tartozik, az 1. oszlop a teljes illeszkedő stringet tartalmazza, a többi oszlop pedig a különféle rögzítő csoportokat.

A nevesített csoportok használata előnyt jelenthet, mert azokból lesznek az eredményül kapott mátrix oszlopnevei.

recipe <- "dissolve 25g sugar in 200ml water"
recipe |> str_match("(\\d+g) .* (\\d+ml)")
     [,1]                 [,2]  [,3]   
[1,] "25g sugar in 200ml" "25g" "200ml"

# use named capture groups
recipe |> str_match("(?<wt>\\d+g) .* (?<vol>\\d+ml)")
                          wt    vol    
[1,] "25g sugar in 200ml" "25g" "200ml"

Ebben a tantervben nem sokat beszéltünk a mátrixokról, de van egy fogalmi dokumentum, amelyet megnézhetsz. A mátrixok nem illenek jól a Tidyverse ökoszisztémájába, pedig már régóta a Base R részei.

Röviden összefoglalva: a mátrixokat olyan vektorként kezeld, amelyeknek 2 indexük van, [rows, cols] sorrendben. Ha valamelyik indexet üresen hagyod, megkapod a teljes sort/oszlopot.

Amikor egyetlen r sort kérsz le a m[r,] kifejezéssel, vagy egyetlen c oszlopot a m[, c] kifejezéssel, a visszaadott érték alapértelmezés szerint vektorrá lapul.

> amounts <- recipe |> str_match("(?<wt>\\d+g) .* (?<vol>\\d+ml)")

# get all of row 1, as a named vector
> amt1 <- amounts[1,]
> amt1
                                       wt                  vol 
"25g sugar in 200ml"                "25g"              "200ml" 

# get a vector element
amt1["wt"] |> unname()
[1] "25g"

Elkerülhetetlenül a str_match_all() még bonyolultabb szerkezetű kimenetet ad:

  • Az eredmény egy lista, minden bemeneti stringhez egy elemmel.
  • Ha csak egyetlen bemeneti string van, a kimenetet a [[1]] indexeléssel bontsd ki a listából, ahogy a Lists fogalom leírja.
  • Minden elem egy mátrix, ugyanolyan oszlopokkal, mint a match() esetében.
  • A mátrix minden sora egy sikeres rögzítés.
mix <- "Mix 200g of sugar, 180g of flour and 150g of butter"

# raw output
> str_match_all(mix, "(\\d+)g")
[[1]]
     [,1]   [,2] 
[1,] "200g" "200"
[2,] "180g" "180"
[3,] "150g" "150"

# we just want the first list element
> str_match_all(mix, "(\\d+)g")[[1]]
     [,1]   [,2] 
[1,] "200g" "200"
[2,] "180g" "180"
[3,] "150g" "150"

# captures are in column 2, so get that as a vector
> str_match_all(mix, "(\\d+)g")[[1]][,2]
[1] "200" "180" "150"

Persze a találatok kudarcot vallhatnak. Ilyenkor az eredmény a különleges NA érték lesz. Készülj fel ennek ellenőrzésére, ahogy a Nothingness fogalom leírja.

# failed match
recipe |> str_match("(not here)")
     [,1] [,2]
[1,] NA   NA  
Note

Az R for Data science megjegyzi:

A str_match() mátrixot ad vissza, így nem különösebben könnyű vele dolgozni.

A lábjegyzettel:

Leginkább azért, mert ebben a könyvben soha nem tárgyaljuk a mátrixokat!

A könyv egyik szerzője írta a stringr könyvtárat is, és implicit módon a saját munkáját kritizálja.

Érdekes lesz látni, hogyan fejlődik ennek a függvénynek a megvalósítása a jövőbeli kiadásokban.

Szerkesztés GitHubon A hivatkozás új ablakban vagy lapon nyílik meg

Tanuld meg a(z) Reguláris kifejezések fogalmat