pH-1
pH-2
pH-3
salinity-1
salinity-2
salinity-3
Các lệnh về biểu thức chính quy
Từ khóa: regular expression; regex
Các bạn tham khảo chuỗi bài giảng về regular expression nhé. [link]
Câu 1
Ta có vector sau:
Làm sạch các ký hiệu -1, -2, -3 ra khỏi các ký tự này, để thu được vector sau:
pH
pH
pH
salinity
salinity
salinity
Ta có nhiều cách để thực hiện, có thể clean từng bước loại các ký tự -1, -2, -3 hoặc dùng trong 1 câu lệnh
Cách 1: Clean từng bước
gsub(pattern = "\\-1", # có thể escape dấu - bằng 2 dấu \\
replacement = "",
a) -> a_clean
cat(a_clean, sep = "\n")pH
pH-2
pH-3
salinity
salinity-2
salinity-3
gsub(pattern = "\\-2", # đè lại chính vector cũ
replacement = "",
a_clean) -> a_clean
cat(a_clean, sep = "\n")pH
pH
pH-3
salinity
salinity
salinity-3
gsub(pattern = "\\-3", # đè lại chính vector cũ
replacement = "",
a_clean) -> a_clean
cat(a_clean, sep = "\n")pH
pH
pH
salinity
salinity
salinity
Cách 2: Dùng regular expression
# lưu ý khoảng trắng cũng là 1 ký tự, ảnh hưởng đến kết quả dò chuỗi
# dùng lệnh OR grouping
gsub(pattern = "-(1|2|3)",
replacement = "",
a) -> a_clean
cat(a_clean, sep = "\n")pH
pH
pH
salinity
salinity
salinity
# dùng lệnh OR từng ký tự
gsub(pattern = "-1|-2|-3",
replacement = "",
a) -> a_clean
cat(a_clean, sep = "\n")pH
pH
pH
salinity
salinity
salinity
gsub(pattern = "\\-1|\\-2|\\-3",
replacement = "",
a) -> a_clean
cat(a_clean, sep = "\n")pH
pH
pH
salinity
salinity
salinity
# dùng digits
gsub(pattern = "-[1-3]",
replacement = "",
a) -> a_clean
cat(a_clean, sep = "\n")pH
pH
pH
salinity
salinity
salinity
# loại bỏ mở rộng, chỉ cần có ký hiệu - và theo sau là numeric thì làm sạch
gsub(pattern = "-[0-9]+",
replacement = "",
a) -> a_clean
cat(a_clean, sep = "\n")pH
pH
pH
salinity
salinity
salinity
Lý thuyết về regular expression
1. Escape character
Dấu . sẽ giúp dò ra tất cả các từ. Muốn chọn dấu chấm ký tự trong chữ ID.1 thì ta phải escape dấu . này bằng lệnh \., tuy nhiên trong R thì dấu \ này có 1 ý nghĩa khác, nên ta phải escape thêm \ để trả về được dấu \, nên sau cùng ta có \\. là để định vị dấu . ký tự. Bài giảng
Ví dụ ta có vector a như sau:
a <- c("lap trinh", "R", "Programming", "study", "ID.1")
cat(a, sep = "\n")lap trinh
R
Programming
study
ID.1
Nếu chỉ dùng dấu . khi đưa vào tham số pattern = "." thì đây là ký hiệu của regular expression, R sẽ dò toàn bộ các thành phần trong vector a.
grep(pattern = ".",
x = a,
value = T,
perl = T) -> out_ok
cat(out_ok, sep = "\n")lap trinh
R
Programming
study
ID.1
Nếu ta “escape” dấu . đó bằng ký hiệu \\ thì R sẽ hiểu đó là dấu chấm ký tự (period character, not a regex character).
grep(pattern = "\\.",
x = a,
value = T,
perl = T) -> out_ok
cat(out_ok, sep = "\n")ID.1
2. Dò con số trong chuỗi
Ta có vector b gồm các ký tự có chứa các con số (digit) như sau:
b <- c("study", "ID.1", "1112", "a12", "0", "code663", "id")
cat(b, sep = "\n")study
ID.1
1112
a12
0
code663
id
Khi dùng ký hiệu d thì đây là ký tự bình thường, R sẽ trích ra các thành phẩn chứa ký tự d này.
grep(pattern = "d",
x = b,
value = T,
perl = T) -> out_ok
cat(out_ok, sep = "\n")study
code663
id
Khi dùng ký hiệu \\d như lệnh regex thì R sẽ tự động trích ra những chuỗi (string) chứa digit.
# trích ra string chứa digit
grep(pattern = "\\d",
x = b,
value = T,
perl = T) -> out_ok
cat(out_ok, sep = "\n")ID.1
1112
a12
0
code663
Khi dùng ký hiệu \\D như lệnh regex thì R sẽ tự động trích ra những chuỗi (string) không chứa digit.
# trích ra string không phải là digit
grep(pattern = "\\D",
x = b,
value = T,
perl = T) -> out_ok
cat(out_ok, sep = "\n")study
ID.1
a12
code663
id
3. Tìm cụm từ trong chuỗi
Cách học các quy tắc tìm và thay thế chuỗi bằng cú pháp regex là ta sẽ thử nghiệm các tham số khác nhau trong lệnh grep() và đánh giá kết quả thu được để hiểu cơ chế lệnh của R, sau đó áp dụng vào tình huống thử nghiệm trên vài chục ký tự trước khi áp dụng vào dữ liệu thực tế.
Nếu việc tìm kiếm phức tạp, ta tách thành nhiều bước nhỏ để lọc dần dữ liệu cho đến khi làm sạch được data đến mức đạt yêu cầu đề bài.
Ta có vector d như sau:
d <- c("happy day",
"going to school",
"Working and feel happy everyday",
"Thanks Happy Birthday",
"I am hhappy",
"Today is Monday")
cat(d, sep = "\n")happy day
going to school
Working and feel happy everyday
Thanks Happy Birthday
I am hhappy
Today is Monday
Để trích ra đúng y chang chữ happy.
# lấy đúng chữ happy `\\b`
grep(pattern = "\\bhappy",
x = d,
perl = T,
value = T) -> out_ok
cat(out_ok, sep = "\n")happy day
Working and feel happy everyday
Để trích ra đúng y chang chữ happy và Happy.
grep(pattern = "\\b(h|H)appy",
x = d,
perl = T,
value = T) -> out_ok
cat(out_ok, sep = "\n")happy day
Working and feel happy everyday
Thanks Happy Birthday
Chỉ trích ra chữ happy mà có dính những ký tự khác, chứ không phải riêng chữ happy
# not-word boundary `\\B` lấy chữ happy có những chữ khác
grep(pattern = "\\Bhappy",
x = d,
perl = T,
value = T) -> out_ok
cat(out_ok, sep = "\n")I am hhappy
Trích ra toàn bộ các chuỗi có chữ happy dù là in hoa hay in thường, có dính các ký tự khác, set tham số ignore.case = T.
grep(pattern = "happy",
x = d,
ignore.case = T, # không quan tâm in hoa hay in thường
perl = T,
value = T) -> out_ok
cat(out_ok, sep = "\n")happy day
Working and feel happy everyday
Thanks Happy Birthday
I am hhappy
Trích ra toàn bộ các chuỗi theo đúng ký tự happy, quan tâm đến việc in hoa và in thường, set tham số ignore.case = F.
grep(pattern = "happy",
x = d,
ignore.case = F, # quan tâm in hoa hay in thường
perl = T,
value = T) -> out_ok
cat(out_ok, sep = "\n")happy day
Working and feel happy everyday
I am hhappy
Ngoài ra trong lệnh
grepcó tham sốfix = TRUEđể cố định việc tìm kiếm chuỗi. Bạn cần test các tham số này trên một vector example để xác nhận xem lệnh regrex hoạt động đúng như yêu cầu hay không, trước khi áp dụng vào real dataset.
4. Thay thế cụm từ
Ta có vector g như sau. Ta cần thay toàn bộ chữ ID (dù viết hoa hay viết thường) theo định dạng CODE_number
g <- c("ID30", "ID12", "ID9", "id11", "id32", "ID_19")
cat(g, sep = "\n")ID30
ID12
ID9
id11
id32
ID_19
Cách này tìm ký tự ID thay bằng CODE nhưng chỗ hai ký hiệu _ thì thay thế bị dư ra.
gsub(pattern = "ID",
replacement = "CODE_",
ignore.case = T,
x = g,
perl = T) -> out_ok
cat(out_ok, sep = "\n")CODE_30
CODE_12
CODE_9
CODE_11
CODE_32
CODE__19
Cách này tìm theo lệnh OR, tuy nhiên đi theo thứ tự ưu tiên, trước khi đến ID_ thì đã bị thay ở chữ ID bằng CODE_ nên vẫn còn ký hiệu _ bị dư ra.
gsub(pattern = "(ID|id|ID_)",
replacement = "CODE_",
x = g,
perl = T) -> out_ok
cat(out_ok, sep = "\n")CODE_30
CODE_12
CODE_9
CODE_11
CODE_32
CODE__19
Cách này OK, ta dùng lệnh OR với thứ tự ưu tiên.
# thứ tự ảnh hưởng đến lệnh gsub
gsub(pattern = "(ID_|ID|id)",
replacement = "CODE_",
x = g,
perl = T) -> g_ok
cat(g_ok, sep = "\n")CODE_30
CODE_12
CODE_9
CODE_11
CODE_32
CODE_19
Để đỡ rắc rối, ta có thể tách thành 2 bước
Bước 1: Thay thế ID bằng CODE, chấp nhận còn một số lỗi chưa sửa được
g <- c("ID30", "ID12", "ID9", "id11", "id32", "ID_19")
cat(g, sep = "\n")ID30
ID12
ID9
id11
id32
ID_19
gsub(pattern = "ID|id",
replacement = "CODE_",
x = g,
perl = T) -> g1
cat(g1, sep = "\n")CODE_30
CODE_12
CODE_9
CODE_11
CODE_32
CODE__19
Bước 2: Tiếp tục thay thế dấu __ dư ra ở bước 1, chuyển về _ cho chuẩn.
gsub(pattern = "__",
replacement = "_",
x = g1,
perl = T) -> g2
g2[1] "CODE_30" "CODE_12" "CODE_9" "CODE_11" "CODE_32" "CODE_19"
cat(g2, sep = "\n")CODE_30
CODE_12
CODE_9
CODE_11
CODE_32
CODE_19
Ví dụ trên cho thấy việc áp dụng regular expression trong R có thể chia chẻ ra thành nhiều bước đơn giản hơn, thay vì tìm cách làm gộp lại trong 1 lệnh thì phải thiết kế cú pháp phức tạp.
Kiểm tra thấy hai cách làm như nhau.
identical(g_ok, g2)[1] TRUE
Tài liệu tham khảo
https://class.tuhocr.com/khoa-hoc/coding-in-r/bai-hoc/regular-expression-trong-r-phan-1/
https://www.regular-expressions.info/cookbook.html