Manipulasi string dengan Reguler Expression (RegEx)

Prerequisites

library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.1.2
## -- Attaching packages --------------------------------------- tidyverse 1.3.1 --
## v ggplot2 3.3.5     v purrr   0.3.4
## v tibble  3.1.4     v dplyr   1.0.7
## v tidyr   1.1.4     v stringr 1.4.0
## v readr   2.0.2     v forcats 0.5.1
## Warning: package 'tidyr' was built under R version 4.1.2
## Warning: package 'dplyr' was built under R version 4.1.2
## -- Conflicts ------------------------------------------ tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()

String Basic

String adalah tipe data yg memperlakukan valuenya sebagai satu kesatuan non-numerical. Di hampir tiap pemrograman, string ditandai dengan "“/’’. Dalam R, keduanya tidak punya perbedaan. Namun demi kerapihan dan readibilitas, lebih baik memulai semuanya dengan”".

ada kalanya juga dalam string itu sendiri, kita ingin memasukkan tanda "" atau ’’. Untuk mengatasi masalah ini, gunakan backlash .

double_quote <- "Dia berkata,\"jadi\""
writeLines(double_quote)
## Dia berkata,"jadi"

Nah, jika misal dalam string kita juga membutuhkan "" atau ’’, maka cara agar kita bisa menghindari galat adalah dengan mengurung kata atau kalimat di dalam "" tersebut dengan  (backlash), seperti contoh di atas.

Namun sedikit berbeda dengan print biasa. Jika kita print var dengan “"”, maka yg muncul adalah tanda escape itu sendiri. Kalau kita ingin melihat output yg sebenarnya, gunakan ‘writeLines()’.

Ada beberapa simbol lain yg bisa dipergunakan untuk memperkaya penulisan variabel string kita. Contoh “”, misalnya, dipergunakan untuk membuat baris baru. dan " dipergunakan untuk membuat tab atau indensasi.

x <- "Aku dan kamu adalah \nbagian tidak terpisahkan dari prosa."
y <- "Jika dia adalah yang terbaik \tmaka aku akan pergi"

writeLines(x)
## Aku dan kamu adalah 
## bagian tidak terpisahkan dari prosa.
writeLines(y)
## Jika dia adalah yang terbaik     maka aku akan pergi

Fungsi str_*()

Meski R basic sudah memiliki fitur untuk manipulasi dan bekerja dengan string. Tool packages yg disediakan stringr memiliki performa yg lebih baik. Berikut adalah beberapa contoh fungsi str_() yg berguna dan paling sering digunakan. Menghitung panjang string

str_length(c("c","R adalah bahasa khusus analisa data",NA))
## [1]  1 35 NA
str_c("x","y")
## [1] "xy"
str_c("a","b","nana")
## [1] "abnana"

Tidak suka penggabungannya?

Buat pemisahan dengan menambahkan argumen ‘sep =’ pada str_c.

str_c("x","a","x", sep = ",")
## [1] "x,a,x"

Jika kita ingin mencetak NA, tambahkan str_replace_na().

# Contoh NA dalam string
str_c("awa",NA)
## [1] NA

Lihat, kan? hasilnya jadi NA; padahal ada satu bagian string yg memiliki nilai. Untuk memastikan value itu tercetak, argumen str_replace_na() jadi sangat diperlukan.

str_c("awa",str_replace_na(NA))
## [1] "awaNA"

contoh lain str_c():

x <- c("abc", NA)
str_c("|-",x,"-|")
## [1] "|-abc-|" NA
str_c("|-",str_replace_na(x),"-|")
## [1] "|-abc-|" "|-NA-|"
str_c("prefix-",c("a","b","c"),"-suffix")
## [1] "prefix-a-suffix" "prefix-b-suffix" "prefix-c-suffix"

Perhatikan polanya. Di sini terlihat bagaimana str_c() memperlakukan seluruh variabel argumennya sebagai vector. Fungsi ini akan menggunakan input vectornya untuk menghasilkan output bagi masing-masing anggota vector.

Oya, jika length dari string = 0, maka secara otomatis str_*() akan membuangnya.

Subsetting string

Selain menghitung panjang dan menggabungkan string, fungsi penting lainnya adalah subsetting atau mengambil sebagian elemen dari variabel string. Fungsi itu adalah str_sub().

str_sub(varname, index_awal (num). index_akhir(num))
a <- c("Apple", "Banana", "Pear")
str_sub(a,1,3)
## [1] "App" "Ban" "Pea"

Angka positif berarti mengambil karakter dari kiri, sedangkan angka negatif mengambil variabel string dari kanan.

str_sub(a,-3,-1)
## [1] "ple" "ana" "ear"

Nah yg cukup memudahkan di sini adalah meski variabel string yg di subsetting lebih pendek dari pada index, funsgi tidak akan menghasilkan error; melainkan hanya memberikan output maksimal yang tersedia.

Matching pattern with Regular Expression

Regular Expression (Regex) adalah bahasa yang mendeskripsikan pola dalam string.

Untuk mulai mempelajari regex, kita akan gunakan fungsi str_view() dan str_view_all(). Fungsi ini memiliki argumen string dan regex, lalu membandingkan kecocokan mereka.

b <- c("apple", "banana", "pear")
str_view(b,"an")

Lihat? dengan regex, saat kita mengetik “an”, sistem akan mencari string yg memiliki pola “an” di dalamnya.

Sekarang, materi regex berikutnya adalah penggunan “.” (titik) yg akan cocok dengan karakter apapun(selain baris baru)

str_view(b, ".a.")

regex “.a.” akan menunjukkan seluruh string yg memiliki “[karakter]a[karakter]” di dalamnya, apapun karakter itu.

Pertanyaan. Lalu bagaimana regex mencocokkan tanda titik itu sendiri? Sama seperti saat menggunakan "" dalam string, kita menggunakan backlash (“") untuk terlepas dari treatment”." sebagai karakter spesial. Perbedaannya kita tidak bisa menggunakannya begitu saja seperti pada "“, karena kita juga akan menggunakan”" dalam regex selain sebagai ‘escape symbol’. Untuk mengatasinya, kita gunakan double backlash. Jadi untuk mengeluarkan “.” dari perilaku regex, kita menulis “\.”

str_view(c("abc","a.c"),"a\\.c")

Lalu bagaimana dengan simbol “" sendiri? Kita gunakan regex (”\\"); yep, empat backlash untuk mencocokkan satu backlash.

Anchor

Dalam pembahasan sebelumnya, kita bisa melihat bahwa regex akan mencocokkan pola dengan bagian string manapun, tanpa perduli posisinya. Untuk memperbaiki ini, ada baiknya kita menentukan ‘anchor’ terlebih dahulu untuk menentukan patokan pola yg diinginkan.

Untuk memastikan bahwa string yg cocok adalah pola tertentu di awal string, gunakan simbol “^”; sedangkan untuk akhir, gunakan “$”

str_view(b, "^a")
str_view(b, "a$")

Jika ingin memastikan regex hanya mencocokkan dengan string utuh, gunakan “^string\(". Selain menggunakan tanda "^" dan "\)”, kita juga bisa menggunakan “. Penggunaannya kurang lebih sama seperti kombinasi”^" dan “$”.

Exercise String

  1. Bagaimana kita mencari kecocokan pola “\(^\)”?
c <- c("dia","$^$")
str_view(c, "\\$\\^\\$")

Penjelasan : Karena “^” dan “$” masing-masing adalah simbol khusus, maka untuk melepaskannya, kita perlu “\” untuk masing-masing simbol.

  1. Temukan regex untuk masing-masing kata string dalam object ‘words’.
  • Yg berawalan ‘y’
str_view_all(words, "^y", match = TRUE)
  • Yg hanya memiliki 3 huruf
str_view_all(words, "^...$", match = TRUE)
  • Yang memiliki jumlah karakter tujuh atau lebih
str_view(words, "^.......", match = TRUE)

Character Classes and Alternatives

Kita sudah mengetahui pola regex “.” yg bisa cocok dengan seluruh karakter (kecuali baris baru). Dalam regex, ada beberapa simbol pola lain yang bisa digunakan : * cocok dengan seluruh digit (angka) * : cocok dengan seluruh whitespace (spasi, baris baru, tab) * [abc] : cocok dengan a,b, atau c * [^abc] : cocok dengan seluruh karakter selain a,b,c

Oya, perlu dipahami [abc] di sini bukan berarti karakter a,b, dan c. Tapi lebih seperti pola susunan karakter tertentu.

Contoh :

str_view(c("abc","a.c","a*c","a c"), "a[.]c", match = TRUE)

Selain class di atas, kita juga bisa menggunakan alternation. Semacam penerapan logika “or” dalam regex.

str_view(c("grey","gray"), "gr(e|a)y", match = TRUE)

Exercise 2.

  1. Cari kecocokan dalam object words
  • dimulai dengan huruf vokal.
str_view_all(words, "^[aiueo]", match = TRUE)
  • Hanya diawali dengan konsonan.
str_view(words, "^[^aiueo]",match = TRUE)
  • Hanya diakhiri dengan “ed” tapi bukan “eed”
str_view(words, "[^e]ed$", match = TRUE)
  • Akhiri dengan “ing” atau “ise”
str_view(words, "ing$|ise$", match = TRUE)
  • Cocokkan pola berikut : “i sebelum e selain setelah c”
str_view(words, "[^c]ie", match = TRUE)
  • Buktikan apakah q selalu diikuti dengan u.
str_view(words, "q", match = TRUE)

Jawab : Iya

  • Cari apakah ada kata dalam words yg memiliki penulisan inggris British
str_view(words, "(ise$|our$)", match = T)

Repetition

Fungsi repetisi digunakan untuk mencari dan menentukan banyaknya perulangan yg kita inginkan dari suatu pola.

Pada bagian sebelumnya, kita tahu bahwa untuk mencari string dengan tujuh karakter, kita menggunakan “…….”.

Adanya fungsi repetisi akan memudahkan kita untuk menulis regex.

Sebelum memberikan contoh, berikut adalah beberapa tipe simbol regex untuk menentukan repetisi. * ? , yang berarti 0 atau 1 * + , yg berarti 1 atau lebih * * , yg berarti 0 atau lebih. Selain ketiga simbol di atas, kita bisa memberi spesifikasi langsung jumlah repetisi yg kita inginkan dengan menuliskan dalam {number of repetition}. Penulisan ini juga ada beberapa bentuk : * {n}, berarti pas sejumlah n repetisi * {n,}, berarti repetisi sejumlah n atau lebih. * {,n}, berarti repetisi paling banyak n * {n,m}, berarti repetisi antara n sampai m

Kembali pada contoh pencarian pola string berkarakter tujuh, dari pada mengetik ‘…….’, kita bisa menuliskan ’.{7,}

str_view(words, ".{7,}", match = T)

Lihat, sama bukan?

Contoh repetisi lain :

e <- "1888 adalah tahun terpanjang dalam penulisan ROMA : MDCCCLXXXVIII"
str_view(e, "CC+")
str_view(e, "CC?")
str_view(e, "C[LX]+")

Catatan tentang repetisi : Secara default, simbol-simbol repetisi akan selalu mencari repetisi paling banyak. Dalam penggunaan {n,m}, repetisi akan mencari pola repetisi m. Kita bisa membuatnya sedikit ‘malas’ dengan menambahkan “?” pada {n,m} jadi {n,m}? untuk membuatnya mencari repetisi paling sedikit.

  • Exercise 4
  1. Temukan kata dalam words yg diawali tiga konsonan
str_view(words, "^[^aiueo]{3}", match = T)
  1. Temukan kata dalam words yg memiliki tiga atau lebih vokal berturut-turut
str_view(words, "[aiueo]{3,}", match = T)
  1. Temukan kata dalam words yg memiliki dua atau lebih pasangan vokal-konsonan
str_view(words, "([aiueo][^aiueo]){2,}", match = T)

Grouping dan backreferences

Tanda kurung () merupakan cara untuk membagi regex yg kompleks menjadi lebih sederhana. Namun selain untuk kerapihan, () juga memungkinkan kita untuk menyimpan pola pada regex untuk kemudian digunakan kembali dalam bentuk backreference menggunakan \nomor refrensi.

contoh :

str_view(words, "^(.).*\\1$", match = T) #artinya kita menyimpan pola karakter tertentu di awal, dan kemudian digunakan kembali pada karakter akhir. Intinya kode regex ini mencari kata dalam words yg diawali dan diakhiri dengan karakter yg sama.

Jumlah nomor akan tergantung pada berapa banyak tanda kurung atau grouping yg dilakukan.

contoh lain :

Cari kata dengan pasangan yg berulang.

str_view(words, "^(..).*\\1", match = T)

Tools

Pada bagian ini, kita akan belajar bagaimana cara untuk : * Menentukan string yang match * Menemukan posisi string yang match * Ekstrak konten string yang match * Mengganti konten string yang match * Memecah string berdasarkan kecocokan pola

Detect Match

Untuk menentukan apakah vector karakter cocok dengan suatu pola, kita menggunakan str_detect(). Fungsi ini akan menghasilkan output vector logis yg sama dengan panjang input

x <- c("apple","banana","pear")
str_detect(x, "e")
## [1]  TRUE FALSE  TRUE

Apa gunanya output ini. Fungsi ini memungkinkan kita untuk melakukan perhitungan berapa banyak kata yg memiliki pola yg kita cari, karena TRUE = 1, dan FALSE = 0

sum(str_detect(words, "^t")) # Menghitung berapa banyak kata yg dimulai dengan "t"
## [1] 65
# Berapa proporsi kata dalam words yg diakhiri dengan huruf vokal?
mean(str_detect(words, "[aiueo]$"))
## [1] 0.2765306

Untuk menunjukkan katanya yg sesuai dengan pola, kita bisa gunakan str_subset() atau str_count()untuk menghitung berapa pola yg ditemukan di tiap string.

str_subset(words, "b$")
## [1] "club" "job"

str_count() akan menghasilkan output berapa banyak pola yg muncul dalam string.

sum(str_count(words, "x$"))
## [1] 4

atau kita bisa mengubah words menjadi tibble dan menerapkan seluruh fungsi manipulasi data padanya.

df <- tibble(word = words, i = seq_along(word))

df %>% filter(str_detect(word, "x$"))
## # A tibble: 4 x 2
##   word      i
##   <chr> <int>
## 1 box     108
## 2 sex     747
## 3 six     772
## 4 tax     841

Exercise for str_detect()

  1. Temukan seluruh kata yang dimulai atau diakhiri dengan “x”.

jawab :

str_subset(words, "^x|x$")
## [1] "box" "sex" "six" "tax"
  1. Temukan seluruh kata yang dimulai dengan vokal dan diakhiri konsonan

Jawab :

str_subset(words, "^[aiueo].*[^aiueo]$")
##   [1] "about"       "accept"      "account"     "across"      "act"        
##   [6] "actual"      "add"         "address"     "admit"       "affect"     
##  [11] "afford"      "after"       "afternoon"   "again"       "against"    
##  [16] "agent"       "air"         "all"         "allow"       "almost"     
##  [21] "along"       "already"     "alright"     "although"    "always"     
##  [26] "amount"      "and"         "another"     "answer"      "any"        
##  [31] "apart"       "apparent"    "appear"      "apply"       "appoint"    
##  [36] "approach"    "arm"         "around"      "art"         "as"         
##  [41] "ask"         "at"          "attend"      "authority"   "away"       
##  [46] "awful"       "each"        "early"       "east"        "easy"       
##  [51] "eat"         "economy"     "effect"      "egg"         "eight"      
##  [56] "either"      "elect"       "electric"    "eleven"      "employ"     
##  [61] "end"         "english"     "enjoy"       "enough"      "enter"      
##  [66] "environment" "equal"       "especial"    "even"        "evening"    
##  [71] "ever"        "every"       "exact"       "except"      "exist"      
##  [76] "expect"      "explain"     "express"     "identify"    "if"         
##  [81] "important"   "in"          "indeed"      "individual"  "industry"   
##  [86] "inform"      "instead"     "interest"    "invest"      "it"         
##  [91] "item"        "obvious"     "occasion"    "odd"         "of"         
##  [96] "off"         "offer"       "often"       "okay"        "old"        
## [101] "on"          "only"        "open"        "opportunity" "or"         
## [106] "order"       "original"    "other"       "ought"       "out"        
## [111] "over"        "own"         "under"       "understand"  "union"      
## [116] "unit"        "university"  "unless"      "until"       "up"         
## [121] "upon"        "usual"

Alternatif jawabab :

kata <- tibble(word = words) %>% filter(str_detect(word,"^[aiueo].*[aiueo]$"))

kata
## # A tibble: 52 x 1
##    word     
##    <chr>    
##  1 able     
##  2 absolute 
##  3 achieve  
##  4 active   
##  5 advertise
##  6 age      
##  7 ago      
##  8 agree    
##  9 also     
## 10 america  
## # ... with 42 more rows
  1. Apakah ada kata yang memiliki satu dari vokal yg berbeda?

jawab :

Penjelasan tentang pertanyaan : karena agak rumit, akan dijelaskan terlebih dahulu apa maksud pertanyaan ini. Pada dasarnya kita diminta untuk mencari kata yang memiliki seluruh vokal di dalamnya (tidak perduli berapa kali perulangan dan urutannya)

kata2 <- tibble(word = words)

words[str_detect(words, "a") & 
         str_detect(words,"i") &
         str_detect(words,"u") & 
         str_detect(words,"e") &
         str_detect(words, "o")]
## character(0)
  1. Apa kata yang memiliki angka huruf vokal terbanyak. Berapa proporsi huruf vokal tertinggi?

Jawab :

kata3 <- kata2 %>% mutate(
  vokal = str_count(word,"[aiueo]"),
  konsonan = str_count(word,"[^aiueo]"),
  panjang = str_length(word),
  prop = vokal/panjang
)

# Kata apa yang memiliki jumlah hururf vokal terbanyak?
kata3 %>% arrange(desc(vokal)) %>% head(5)
## # A tibble: 5 x 5
##   word        vokal konsonan panjang  prop
##   <chr>       <int>    <int>   <int> <dbl>
## 1 appropriate     5        6      11 0.455
## 2 associate       5        4       9 0.556
## 3 available       5        4       9 0.556
## 4 colleague       5        4       9 0.556
## 5 encourage       5        4       9 0.556
# Kata apa yang memiliki proporsi huruf vokal terbanyak?
kata3 %>% arrange(desc(prop)) %>% head(5)
## # A tibble: 5 x 5
##   word  vokal konsonan panjang  prop
##   <chr> <int>    <int>   <int> <dbl>
## 1 a         1        0       1 1    
## 2 area      3        1       4 0.75 
## 3 idea      3        1       4 0.75 
## 4 age       2        1       3 0.667
## 5 ago       2        1       3 0.667

Extract matches

Fungsi dalam stringr untuk mendapatkan teks aktual dari pola adalah str_extract(). Untuk bagian ini, kita akan menggunakan contoh lain dari object ‘sentences’. Pertama, mari kita lihat apakah object ini tersedia untuk R versi 4.1.1

head(sentences)
## [1] "The birch canoe slid on the smooth planks." 
## [2] "Glue the sheet to the dark blue background."
## [3] "It's easy to tell the depth of a well."     
## [4] "These days a chicken leg is a rare dish."   
## [5] "Rice is often served in round bowls."       
## [6] "The juice of lemons makes fine punch."

Sekarang, untuk pertama, kita akan mencoba menemukan kalimat yang mengandung warna. Untuk itu, pertama, kita buat vector nama-nama warna dan kemudian mengubahnya single regex.

colour <- c("red","orange","yellow","green","blue","purple")
colour_match <- str_c(colour, collapse = "|")
colour_match
## [1] "red|orange|yellow|green|blue|purple"

Kenapa perlu dijadikan satu dan memiliki | ? Karena ini adalah bentuk regex dengan fungsi logika atau yang menjadi acuan kita untuk mencari pola dalam sentences.

has_colour <- str_subset(sentences, colour_match)
has_colour
##  [1] "Glue the sheet to the dark blue background."       
##  [2] "Two blue fish swam in the tank."                   
##  [3] "The colt reared and threw the tall rider."         
##  [4] "The wide road shimmered in the hot sun."           
##  [5] "See the cat glaring at the scared mouse."          
##  [6] "A wisp of cloud hung in the blue air."             
##  [7] "Leaves turn brown and yellow in the fall."         
##  [8] "He ordered peach pie with ice cream."              
##  [9] "Pure bred poodles have curls."                     
## [10] "The spot on the blotter was made by green ink."    
## [11] "Mud was spattered on the front of his white shirt."
## [12] "The sofa cushion is red and of light weight."      
## [13] "The sky that morning was clear and bright blue."   
## [14] "Torn scraps littered the stone floor."             
## [15] "The doctor cured him with these pills."            
## [16] "The new girl was fired today at noon."             
## [17] "The third act was dull and tired the players."     
## [18] "A blue crane is a tall wading bird."               
## [19] "Lire wires should be kept covered."                
## [20] "It is hard to erase blue or red ink."              
## [21] "The wreck occurred by the bank on Main Street."    
## [22] "The lamp shone with a steady green flame."         
## [23] "The box is held by a bright red snapper."          
## [24] "The prince ordered his head chopped off."          
## [25] "The houses are built of red clay bricks."          
## [26] "The red tape bound the smuggled food."             
## [27] "Nine men were hired to dig the ruins."             
## [28] "The flint sputtered and lit a pine torch."         
## [29] "Hedge apples may stain your hands green."          
## [30] "The old pan was covered with hard fudge."          
## [31] "The plant grew large and green in the window."     
## [32] "The store walls were lined with colored frocks."   
## [33] "The purple tie was ten years old."                 
## [34] "Bathe and relax in the cool green grass."          
## [35] "The clan gathered on each dull night."             
## [36] "The lake sparkled in the red hot sun."             
## [37] "Mark the spot with a sign painted red."            
## [38] "Smoke poured out of every crack."                  
## [39] "Serve the hot rum to the tired heroes."            
## [40] "The couch cover and hall drapes were blue."        
## [41] "He offered proof in the form of a lsrge chart."    
## [42] "A man in a blue sweater sat at the desk."          
## [43] "The sip of tea revives his tired friend."          
## [44] "The door was barred, locked, and bolted as well."  
## [45] "A thick coat of black paint covered all."          
## [46] "The small red neon lamp went out."                 
## [47] "Paint the sockets in the wall dull green."         
## [48] "Wake and rise, and step into the green outdoors."  
## [49] "The green light in the brown box flickered."       
## [50] "He put his last cartridge into the gun and fired." 
## [51] "The ram scared the school children off."           
## [52] "Tear a thin sheet from the yellow pad."            
## [53] "Dimes showered down from all sides."               
## [54] "The sky in the west is tinged with orange red."    
## [55] "The red paper brightened the dim stage."           
## [56] "The hail pattered on the burnt brown grass."       
## [57] "The big red apple fell to the ground."
matches <- str_extract(has_colour,colour_match)
head(matches)
## [1] "blue" "blue" "red"  "red"  "red"  "blue"

Pertama, perlu kita tekankan kembali apa output dari fungsi str_subset dan str_extract. Dengan str_subset() kita akan hanya akan menghasilkan string yang memiliki pola yang cocok. Seperti has_colour di atas, dia akan menghasilkan variabel string yang memiliki value dalam colour_match. Sedangkan dengan str_extract, dia akan melihat seluruh variabel string, memberi nilai NA pada string yang tidak memiliki pola cocok. Jadi alasan kenapa kita repot-repot menulis dua fungsi tersebut pada kode di atas adalah untuk mengikuti alur logika; pertama, kita buat objek string yang berisi warna, lalu dari objek tersebut, kita extract pola kata yang kita cari.

Catatan tambahan :

Coba perhatikan hasil str_subset… ternyata, terdapat beberapa string dalam sentences yang memiliki lebih dari satu warna dalam satu string. Lalu kenapa saat di extract, hanya muncul satu? alasannya karena fungsi str_extract sudah didesain untuk hanya mengambil kata pertama yang cocok dalam pola. Fungsi ini dibuat untuk menciptakan struktur data yang lebih sederhana. Untuk melihat seluruh kata yang cocok dalam satu string, kita bisa gunakan str_extarct_all(); dan kita akan paham kenapa fungsi ‘hanya extract pertama’ jadi masuk akal.

head(str_extract_all(has_colour, colour_match),20)
## [[1]]
## [1] "blue"
## 
## [[2]]
## [1] "blue"
## 
## [[3]]
## [1] "red"
## 
## [[4]]
## [1] "red"
## 
## [[5]]
## [1] "red"
## 
## [[6]]
## [1] "blue"
## 
## [[7]]
## [1] "yellow"
## 
## [[8]]
## [1] "red"
## 
## [[9]]
## [1] "red"
## 
## [[10]]
## [1] "green"
## 
## [[11]]
## [1] "red"
## 
## [[12]]
## [1] "red"
## 
## [[13]]
## [1] "blue"
## 
## [[14]]
## [1] "red"
## 
## [[15]]
## [1] "red"
## 
## [[16]]
## [1] "red"
## 
## [[17]]
## [1] "red"
## 
## [[18]]
## [1] "blue"
## 
## [[19]]
## [1] "red"
## 
## [[20]]
## [1] "blue" "red"

Lihat kan? struktur data yg muncul menjadi list. Dan kita bisa lihat bagaimana, pada list no 20, terdapat dua string warna yang muncul.

Ada cara yang cukup bagus untuk mengatasi tampilan data yang kurang enak ini. Yaitu dengan menambahkan argumen simplify = T. Tampilan data akan berubah menjadi matrix.

more <- sentences[str_count(sentences,colour_match) > 1]
str_extract_all(more, colour_match, simplify = T)
##      [,1]     [,2] 
## [1,] "blue"   "red"
## [2,] "green"  "red"
## [3,] "orange" "red"

Exercise extract

  1. Dalam hasil subset dan extarct di atas, kita menemukan kata ‘flickered’ yang bukan warna juga dimasukkan dalam hasil penemuan pola. Buat regex agar kesalahan seperti ini tidak terjadi.

jawab :

kalimat <- tibble(first_word = str_extract(sentences, "\\b\\w*\\b"))
kalimat %>% group_by(first_word) %>% summarise(jumlah=n()) %>% 
  arrange(desc(jumlah))
## # A tibble: 260 x 2
##    first_word jumlah
##    <chr>       <int>
##  1 The           262
##  2 A              72
##  3 He             24
##  4 It             14
##  5 We             13
##  6 They           10
##  7 She             9
##  8 There           7
##  9 Take            5
## 10 This            5
## # ... with 250 more rows
  1. Seluruh kata yang berakhiran ‘ing’
kataSen <- str_extract_all(sentences,"\\b\\w*\\b", simplify = T)
kataSen2 <- str_subset(kataSen,"ing$")
kataSen2
##  [1] "Adding"    "Bring"     "Bring"     "king"      "filing"    "thing"    
##  [7] "whistling" "winding"   "lodging"   "swing"     "ring"      "bring"    
## [13] "waiting"   "ring"      "glaring"   "morning"   "morning"   "puzzling" 
## [19] "spring"    "playing"   "making"    "bring"     "thing"     "spring"   
## [25] "living"    "walking"   "timing"    "raging"    "dying"     "wearing"  
## [31] "wading"    "sing"      "sleeping"  "spring"    "winding"   "landing"  
## [37] "nothing"   "moving"    "working"   "morning"   "making"    "sleeping" 
## [43] "sinking"   "nothing"   "king"      "shipping"  "ring"      "changing" 
## [49] "drenching" "evening"   "ring"      "painting"  "spring"
  1. Seluruh kata plural (diakhiri ‘s’ atau ‘es’)
kataSen3 <- str_subset(kataSen,"(s|es)$")
kataSen3
##   [1] "Press"      "Sickness"   "Cars"       "This"       "Always"    
##   [6] "Cats"       "Thieves"    "Leaves"     "Clothes"    "Guess"     
##  [11] "Farmers"    "Schools"    "Whitings"   "This"       "Ducks"     
##  [16] "His"        "Boards"     "Glass"      "Pages"      "Brass"     
##  [21] "This"       "Roads"      "His"        "Hats"       "This"      
##  [26] "Bottles"    "Oats"       "This"       "Press"      "His"       
##  [31] "Clams"      "Bribes"     "Footprints" "Calves"     "Dimes"     
##  [36] "Dots"       "s"          "days"       "is"         "hogs"      
##  [41] "hours"      "fires"      "is"         "words"      "grass"     
##  [46] "pins"       "is"         "is"         "boss"       "plus"      
##  [51] "is"         "thistles"   "was"        "pencils"    "pirates"   
##  [56] "is"         "was"        "scraps"     "is"         "burns"     
##  [61] "tales"      "miles"      "has"        "cobs"       "tongs"     
##  [66] "petals"     "hostess"    "loss"       "wires"      "is"        
##  [71] "ads"        "this"       "brothers"   "houses"     "flavors"   
##  [76] "pills"      "pears"      "seats"      "shelves"    "apples"    
##  [81] "curls"      "cans"       "clouds"     "is"         "s"         
##  [86] "is"         "brings"     "rows"       "zones"      "is"        
##  [91] "logs"       "plans"      "rings"      "takes"      "takes"     
##  [96] "winds"      "asks"       "ones"       "s"          "takes"     
## [101] "is"         "makes"      "news"       "takes"      "is"        
## [106] "is"         "coins"      "pants"      "buns"       "stems"     
## [111] "clothes"    "bills"      "glasses"    "years"      "eyelids"   
## [116] "was"        "dress"      "pears"      "plans"      "hands"     
## [121] "makes"      "clothes"    "pickles"    "matters"    "was"       
## [126] "is"         "was"        "brass"      "lobes"      "stories"   
## [131] "is"         "words"      "moss"       "facts"      "flaps"     
## [136] "loss"       "was"        "eggs"       "nerves"     "maps"      
## [141] "pods"       "is"         "is"         "hands"      "gloss"     
## [146] "seals"      "troops"     "was"        "bombs"      "streets"   
## [151] "grass"      "was"        "was"        "is"         "pants"     
## [156] "was"        "was"        "was"        "was"        "keeps"     
## [161] "leads"      "was"        "is"         "soldiers"   "busses"    
## [166] "was"        "was"        "seems"      "is"         "as"        
## [171] "dogs"       "its"        "is"         "problems"   "results"   
## [176] "poodles"    "holes"      "is"         "his"        "was"       
## [181] "ladies"     "his"        "is"         "islands"    "is"        
## [186] "was"        "was"        "walls"      "us"         "records"   
## [191] "is"         "is"         "less"       "is"         "s"         
## [196] "piles"      "is"         "was"        "shares"     "means"     
## [201] "cuts"       "was"        "costs"      "is"         "pins"      
## [206] "drifts"     "ashes"      "is"         "is"         "was"       
## [211] "lanterns"   "cuts"       "is"         "tales"      "was"       
## [216] "hours"      "was"        "drifts"     "mails"      "was"       
## [221] "words"      "his"        "sockets"    "is"         "his"       
## [226] "makes"      "his"        "comes"      "grows"      "was"       
## [231] "is"         "bills"      "kits"       "saves"      "was"       
## [236] "was"        "comes"      "was"        "puts"       "his"       
## [241] "lemons"     "stockings"  "was"        "is"         "chicks"    
## [246] "lives"      "was"        "makes"      "was"        "was"       
## [251] "friends"    "orders"     "lists"      "is"         "events"    
## [256] "tastes"     "is"         "is"         "is"         "does"      
## [261] "was"        "was"        "s"          "was"        "is"        
## [266] "compass"    "was"        "is"         "its"        "was"       
## [271] "fans"       "ties"       "makes"      "as"         "funds"     
## [276] "gets"       "as"         "his"        "less"       "is"        
## [281] "fits"       "was"        "was"        "unless"     "soldiers"  
## [286] "is"         "as"         "cats"       "colds"      "names"     
## [291] "restores"   "his"        "protects"   "cuffs"      "kinds"     
## [296] "means"      "grapes"     "figs"       "is"         "tales"     
## [301] "ways"       "this"       "this"       "this"       "is"        
## [306] "is"         "is"         "its"        "was"        "kids"      
## [311] "gets"       "across"     "funds"      "guests"     "has"       
## [316] "runs"       "his"        "is"         "peas"       "is"        
## [321] "comes"      "biscuits"   "informs"    "is"         "takes"     
## [326] "fits"       "his"        "was"        "was"        "bushes"    
## [331] "makes"      "is"         "helps"      "across"     "his"       
## [336] "makes"      "across"     "costs"      "logs"       "his"       
## [341] "less"       "curls"      "was"        "is"         "us"        
## [346] "miles"      "spoils"     "binds"      "leaves"     "was"       
## [351] "as"         "changes"    "secrets"    "is"         "gives"     
## [356] "lines"      "goes"       "makes"      "trims"      "cents"     
## [361] "peas"       "is"         "is"         "his"        "rags"      
## [366] "chairs"     "was"        "priceless"  "makes"      "is"        
## [371] "was"        "revives"    "was"        "is"         "was"       
## [376] "needs"      "requests"   "edges"      "goes"       "ears"      
## [381] "seems"      "has"        "always"     "as"         "this"      
## [386] "waters"     "tunes"      "is"         "business"   "branches"  
## [391] "less"       "his"        "is"         "useless"    "sums"      
## [396] "factors"    "his"        "parts"      "gives"      "improves"  
## [401] "orders"     "less"       "its"        "leaves"     "eyes"      
## [406] "was"        "this"       "stories"    "toys"       "his"       
## [411] "writes"     "groups"     "buyers"     "as"         "its"       
## [416] "is"         "his"        "needs"      "hands"      "tones"     
## [421] "was"        "discuss"    "as"         "years"      "sometimes" 
## [426] "lines"      "needs"      "us"         "fails"      "woods"     
## [431] "fevers"     "is"         "always"     "restless"   "robins"    
## [436] "itches"     "pockets"    "lasts"      "drapes"     "glasses"   
## [441] "gives"      "limits"     "stones"     "is"         "waves"     
## [446] "his"        "is"         "shoes"      "words"      "is"        
## [451] "friends"    "says"       "trinkets"   "blades"     "reads"     
## [456] "flames"     "was"        "was"        "speaks"     "friends"   
## [461] "boys"       "tumbles"    "glass"      "moves"      "was"       
## [466] "grass"      "miss"       "sides"      "is"         "its"       
## [471] "is"         "batches"    "needs"      "contents"   "as"        
## [476] "times"      "bowls"      "us"         "is"         "pass"      
## [481] "s"          "gas"        "kittens"    "books"      "wheels"    
## [486] "steps"      "drifts"     "hikes"      "weeks"      "was"       
## [491] "parts"      "things"     "contents"   "brass"      "is"        
## [496] "times"      "s"          "scores"     "is"         "is"        
## [501] "leaves"     "pills"      "inches"     "is"         "wonders"   
## [506] "was"        "taps"       "ribbons"    "nets"       "rings"     
## [511] "is"         "slides"     "compass"    "drinks"     "others"    
## [516] "is"         "fans"       "is"         "cross"      "is"        
## [521] "crackers"   "days"       "shelves"    "was"        "mules"     
## [526] "edges"      "brass"      "natives"    "seeds"      "wanders"   
## [531] "lingers"    "Mondays"    "minds"      "was"        "lines"     
## [536] "cents"      "mats"       "his"        "us"         "hearts"    
## [541] "was"        "this"       "this"       "was"        "its"       
## [546] "grass"      "is"         "is"         "rocks"      "looks"     
## [551] "parades"    "amounts"    "blocks"     "brass"      "needs"     
## [556] "leaves"     "sheets"     "was"        "coins"      "planks"    
## [561] "bonds"      "grass"      "strokes"    "slices"     "eggs"      
## [566] "gifts"      "his"        "figures"    "blocks"     "clothes"   
## [571] "tacks"      "class"      "brass"      "bricks"     "ruins"     
## [576] "eyes"       "was"        "s"          "minutes"    "frocks"    
## [581] "plans"      "takes"      "as"         "contents"   "was"       
## [586] "s"          "grass"      "us"         "objects"    "names"     
## [591] "items"      "heroes"     "was"        "his"        "was"       
## [596] "things"     "as"         "s"          "clowns"     "words"     
## [601] "shoes"      "inches"     "mass"       "others"     "is"        
## [606] "planes"     "fields"     "is"         "blows"      "s"         
## [611] "grass"      "blows"      "his"        "s"          "days"      
## [616] "boards"     "circus"     "glass"      "actress"    "pipes"     
## [621] "players"    "friends"    "crackers"   "brass"      "rays"      
## [626] "us"         "sticks"     "s"          "dress"      "ways"      
## [631] "days"       "this"       "cherries"   "sparks"     "days"      
## [636] "times"      "outdoors"   "was"        "faults"     "ruins"     
## [641] "turns"      "tropics"    "backs"      "useless"    "chorus"    
## [646] "books"      "ends"       "designs"    "leaves"     "rings"     
## [651] "dishes"     "is"         "hops"       "clips"      "shrubs"

Grouping match

Kembali pada penggunaan tanda kurung () dalam regex dan stringr. Kita sudah tahu bahwa () untuk mengklarifikasikan precedence dan backreferences, selain itu ternyata penggunaan () bisa diartikan sebagai grouping pola. Di mana kita bisa membuat membuat beberapa group pola, dan lalu menggunakan str_match untuk menarik kalimat yg cocok, sekaligus membuat kolom untuk masing-masing grup tersebut.

noun <- "(a|the) ([^ ]+)"
has_noun <- sentences %>% str_subset(noun) %>%
  head(10)

has_noun %>% str_extract(noun)
##  [1] "the smooth" "the sheet"  "the depth"  "a chicken"  "the parked"
##  [6] "the sun"    "the huge"   "the ball"   "the woman"  "a helps"
has_noun %>% str_match(noun)
##       [,1]         [,2]  [,3]     
##  [1,] "the smooth" "the" "smooth" 
##  [2,] "the sheet"  "the" "sheet"  
##  [3,] "the depth"  "the" "depth"  
##  [4,] "a chicken"  "a"   "chicken"
##  [5,] "the parked" "the" "parked" 
##  [6,] "the sun"    "the" "sun"    
##  [7,] "the huge"   "the" "huge"   
##  [8,] "the ball"   "the" "ball"   
##  [9,] "the woman"  "the" "woman"  
## [10,] "a helps"    "a"   "helps"
has_noun %>% str_match_all(noun)
## [[1]]
##      [,1]         [,2]  [,3]    
## [1,] "the smooth" "the" "smooth"
## 
## [[2]]
##      [,1]        [,2]  [,3]   
## [1,] "the sheet" "the" "sheet"
## [2,] "the dark"  "the" "dark" 
## 
## [[3]]
##      [,1]        [,2]  [,3]   
## [1,] "the depth" "the" "depth"
## [2,] "a well."   "a"   "well."
## 
## [[4]]
##      [,1]        [,2] [,3]     
## [1,] "a chicken" "a"  "chicken"
## [2,] "a rare"    "a"  "rare"   
## 
## [[5]]
##      [,1]         [,2]  [,3]    
## [1,] "the parked" "the" "parked"
## 
## [[6]]
##      [,1]      [,2]  [,3] 
## [1,] "the sun" "the" "sun"
## 
## [[7]]
##      [,1]        [,2]  [,3]   
## [1,] "the huge"  "the" "huge" 
## [2,] "the clear" "the" "clear"
## 
## [[8]]
##      [,1]       [,2]  [,3]  
## [1,] "the ball" "the" "ball"
## 
## [[9]]
##      [,1]        [,2]  [,3]   
## [1,] "the woman" "the" "woman"
## 
## [[10]]
##      [,1]           [,2]  [,3]      
## [1,] "a helps"      "a"   "helps"   
## [2,] "the evening." "the" "evening."

Selain str_match, tool lain yang bergunas adalah : * str_replace() untuk mengganti pola yg ditemukan dengan karakter lain * str_replace_all() untuk memberi vektor karakter yg perlu diganti dan penggantinya * str_split untuk memecah kalimat menjadi kata berdasar karakter tertentu * str_locate dan str_locate_all() untuk memberi kita posisi awal dan akhir pola yang kita inginkan.

Other type of pattern

Saat kita menulis pola regex dalam "". Sebenarnya ini adalah bentuk pendek dari fungsi regex yang sebenarnya, di mana :

str_view(sentences, regex("..."))

Kita bisa memunculkan kembali regex() untuk mengatur beberapa argumen yang penting.

  • ignore_case = TRUE; pengaturan ini akan mengabaikan huruf kecil dan kapital, sehingga pencarian pola bisa lebih luas.
  • multiline = TRUE; pengaturan ini memungkinkan pencarian pola dari awal hingga akhir tiap baris, dari pada hanya per string.
  • comment = TRUE; pengaturan ini memungkinkan untuk menuliskan komen dan catatan sehingga pola regex bisa lebih mudah dipahami ke depannya.
  • dotall = TRUE; memungkinkan “.” untuk cocok dengan semua karakter termasuk

Fungsi lain yang menggunakan regex.

Selain str_, fungsi lain yang menggunakan regex adalah : apropos() ; fungsi ini bertujuan untuk mencaari seluruh objek dalam global environment. contoh

apropos("replace")
## [1] "%+replace%"       "replace"          "replace_na"       "setReplaceMethod"
## [5] "str_replace"      "str_replace_all"  "str_replace_na"   "theme_replace"
  • dir() ; fungsi ini bertujuan untuk menunjukkan seluruh file dalam direktori. argument pattern = … akan menunjukkan file yang memiliki kecocokan dengan pola yang kita tulis.
dir(pattern = "\\.Rmd$")
## [1] "Wrangle-String.Rmd"

stringi

stringi adalah paket yang menjadi pondasi dari stringr. Terdapat lebih banyak fungsi yang mungkin bisa berguna jika kita tidak menemukannya dalam stringr.