Hỏi về check regex tiếng việt
Cho mình hỏi là mình muốn check đoạn text tiếng việt sau bằng regex. Mình muốn nó bắt vào 'MU' nhưng nó đang bắt vào 'mu' của từ 'muốn'. Vậy nguyên nhân là do sao ạ?
let test = 'muốn học tập MU';
const regexp = new RegExp(/\bmu\b/, 'i'); // showing how to pass optional flags
console.log(test.match(regexp)); // > Array ["mu"]
Nhưng nếu sửa 'muốn' thành 'mueốn' thì ok:
let test = 'mueốn học tập MU';
const regexp = new RegExp(/\bmu\b/, 'i'); // showing how to pass optional flags
console.log(test.match(regexp)); // > Array ["MU"]
1 CÂU TRẢ LỜI
\b xác định vị trí đầu chuỗi, cuối chuỗi hoặc giữa 2 kí tự 1 là word character (\w), 2 là non-word character (\W) Và vì các kí tự tiếng việt (ê, ô, ế...), không phải là word character (có thể test bằng \w) nên trường hợp của 'muốn' đúng với pattern \bmu\b (\b thứ nhất là đầu chuỗi, \b thứ hai là giữa 1 word và non-word)
vậy ở trong đoạn text ‘muốn học tập MU' mình muốn nó bắt vào ‘MU’ thì viết regex như nào nhỉ bạn?
@bacode Bạn có thể dùng cú pháp lookaround để tìm (không phải phiên bản nào cũng hỗ trợ. Như google dùng RE2, không hỗ trợ) Tìm tất cả các chuỗi MU, mà không đứng sau hoặc đứng trước bất kì kí tự gì ngoài whitespace
let test = 'MU muốn học tậpMU MU';
let regexp = new RegExp(/(?<![^\s])mu(?![^\s])/, 'ig'); // showing how to pass optional flags
console.log(test.match(regexp)); // > Array ["MU", "MU]
@Sorrow chrome với safari trên iphone không được hỗ trợ à bạn?
@bacode Mình đang nói đến các loại engine (library) của regular expression (Regex). Regex trên thực tế là các thư viện được các ngôn ngữ lập trình sử dụng, do đó, mỗi một thư viện lại cung cấp 1 bộ cú pháp khác nhau. Có những cú pháp chung, phổ biến thì thư viện nào cũng hỗ trợ. Có những cái như cú pháp lookaround mình dùng bên trên, lại không được hỗ trợ 100%.
Javascript dùng thư viện XRegExp, hỗ trợ positive và negative lookaround, chạy trên Internet Explorer 5.5+, Firefox 1.5+, Chrome, Safari 3+, and Opera 11+ Nguồn: http://xregexp.com/
Các bộ g suite của Google như google sheet (hàm regexmatch(), regexextract() ) lại dùng thư viện là RE2. Thư viện này hỗ trợ kém và thiếu nhiều cú pháp như lookaround chẳng hạn Nguồn: https://github.com/google/re2
Tham khảo thêm: https://en.wikipedia.org/wiki/Comparison_of_regular-expression_engines
@Sorrow Mình đang làm trên reactjs. Thì dùng lib XRegExp này ok k bạn?
@bacode Từ ES2018 thì JS hỗ trợ lookahead, lookbehind rồi nên không cần dùng lib ngoài vẫn có thể giải được bài toán của bạn nhé (Kể cả với reactjs)
Nguồn: https://en.wikipedia.org/wiki/Comparison_of_regular-expression_engines#Part_1
@Sorrow đoạn mình cần check sẽ implement như nào nhỉ bạn?
@bacode Mình có viết 1 ví dụ ở trên rồi đó
@Sorrow mình thử đoạn này của bạn chạy ok. nhưng nó ko hỗ trợ trên safari. Cả chrome, safari trên iphone nữa
let test = 'MU muốn học tậpMU MU'; let regexp = new RegExp(/(?<![^\s])mu(?![^\s])/, 'ig'); // showing how to pass optional flags console.log(test.match(regexp)); // > Array ["MU", "MU]
@bacode Bạn thử lại đoạn này xem nhé
let test = 'MU muốn học tậpMU MU';
let regexp = new RegExp(/\bmu\b(?![\u00C0-\u1EF3])/, 'ig'); // Bắt tất cả các chuỗi "mu" mà không theo sau bởi 1 kí tự latin extend (kí tự tiếng việt)
console.log(test.match(regexp)); // > Array ["MU", "MU]
@Sorrow Sao nó không bắt được Đà Nẵng nhỉ bạn?
let test = 'Đà Nẵng muốn học tậpMU MU';
let regexp = new RegExp(/\bĐà Nẵng\b(?![\u00C0-\u1EF3])/, 'ig');
console.log(test.match(regexp)); // > null
@bacode Như mình đã nói, \b xác định vị trí giữa 1 word và non-word. Và 'Đ' là một non-word, trước đó lại không có 1 word nào cả, nên pattern không hoạt động được.
Thêm 1 word bất kì vào trước 'Đ', hoặc bỏ anchor \b ban đầu đi thì code chạy.
let test = 'aĐà Nẵng muốn học tậpMU MU';
let regexp = new RegExp(/\bĐà Nẵng\b(?![\u00C0-\u1EF3])/, 'ig');
console.log(test.match(regexp)); // > 'Đà Nẵng
let test = 'Đà Nẵng muốn học tậpMU MU';
let regexp = new RegExp(/Đà Nẵng\b(?![\u00C0-\u1EF3])/, 'ig');
console.log(test.match(regexp)); // > 'Đà Nẵng
@Sorrow vậy mình muốn cái text mình truyền vào là động có thể lúc là Đà Nẵng lúc là MU thì có cách nào check đc cho cả 2 trường hợp ko nhỉ bạn?
@bacode Bạn muốn có 1 lời giải chung cho một bài toán thì cũng hơi phức tạp nhỉ.
Theo mình nghĩ, nếu cụm từ bạn cần bắt nó là 1 từ có nhiều chữ cái, từ có 2 tiếng trở lên, thì bạn có thể search thằng từ đó /string/ mà không sợ nó bị lẫn do ghép vần.
Còn nếu chuỗi bạn cần bắt nó là 1 cụm kí tự, dễ bị lẫn vào các từ khi ghép vần (như mu bị lẫn vào muốn, uống lẫn vào xuống), thì bạn có thể dùng các pattern mình có nêu ở trên.
Vì bản chất việc chúng ta cố làm nãy giờ là bắt 1 chuỗi đứng riêng không bị lẫn vào các từ khác (do ghép vần) nhở.
@Sorrow ý bạn là sẽ dùng if else để check r chọn regex phù hợp à?
Dùng new RegExp thì phải escape back slash \ nữa. Ví dụ: \w thành \\w. Cứ dùng reg ex bình thường thôi bạn, ví dụ: let reg =/abcd/