Toàn tập về biểu thức chính quy RegEx trong Javascript

Trong bài này tất cả chúng ta sẽ khám phá về biểu thức chính quy trong javascript, hay còn gọi là RegEx trong javascript. Đây là thư viện được dùng để giải quyết và xử lý chuỗi nâng cao nên rất khó học .

test php

banquyen png

Bài viết này được đăng tại

freetuts.net

, không được copy dưới mọi hình thức.

Như ta biết, regular expression hoạt động theo quy tắc so khớp, va lấy kết quả của sự so khớp đó thông qua những quy tắc mà thư viện RegEx đưa ra. Dựa vào những quy tắc này, lập trình viên sẽ viết thành những biểu thức và áp dụng vào bài toán của mình.

Để tiện cho việc giải thích thì mình xin có một vài lưu ý như sau:

  • Biểu thức chính quy viết trong tiếng Anh là regular expression
  • Regular expression là một thuật ngữ, và chữ viết tắt của nó là RegEx.
  • => Vì vậy, khi nhắc đến ba cụm từ này thì bạn phải hiểu nó là một nhé.

1. RegEx trong Javascript là gì?

RegEx ( regular expression ) là tập hợp những quy tắc, dựa vào những quy tắc này ta sẽ viết ra những biểu thức so khớp giữa những chuỗi với nhau. Đây là một thư viện nâng cao được tích hợp sẵn trong đối tượng người dùng RegExp của Javascript .
Không chỉ ở javascript, thư viện RegEx còn được tích hợp ở hầu hết những ngôn từ lập trình lúc bấy giờ. Vì vậy, khi bạn đọc xong bài này và hiểu hết bài rồi, thì qua những ngôn từ khác sẽ rất dễ học .

Mình sẽ lấy một ví dụ cực kì đơn giản thế này. Để so sánh hai chuỗi có bằng nhau hay không thì ta sử dụng toán tử bằng =. Để kiểm tra chuỗi con có xuất hiện trong chuỗi cha hay không thì ta có thể sử dụng hàm substring.

Nhưng để tìm một chuỗi bắt đầu bằng chữ c và tiếp theo là 5 chữ cái in thường thì làm thế nào? Gặp trường hợp này thì hãy nghĩ đến ngay biểu thức chính quy regular expression nhé.

Trong Javascript thì regular expression là một chuỗi, nhưng nó không được bao quanh bởi cặp dấu nháy đơn ' hoặc nháy kép " mà nó được bao quanh bởi cặp dấu /.

Cú pháp để tạo một chuỗi RegEx như sau:

/pattern/modifiers

Trong đó:

  • pattern là chuỗi Regular Expression
  • modifiers là thông số cấu hình cho chuỗi pattern, và nó có các giá trị sau:
    • i : so khớp không quan tâm đến chữ hoa chữ thường
    • g : so khợp toàn bộ chuỗi cần tìm
    • m : so khớp luôn cả các dữ liệu xuống dòng (multiline)

Ví dụ: Pattern kiểm tra chuỗi có tồn tại chữ “freetuts” không, không phân biệt chữ hoa chữ thường và tìm toàn bộ tài liệu.

var pattern = /freetuts/igm;

Trong ví dụ này thì :

  • Pattern là freetuts
  • Modifiers là igm, tức là so khớp toàn bộ kể cả xuống dòng và không quan tâm đến chữ in hoa hay in thường

2. Hàm test() trong javascript RegEx

Để kiểm thử một biểu thức regular expression thì chúng ta sẽ sử dụng hàm test. Cú pháp của nó như sau:

/pattern/.test(string);

Trong đó pattern chính là biểu thức chính quy, string chính là chuỗi cần tìm.

Giá trị của hàm này sẽ trả về true nếu tìm thấy, và false nếu không tìm thấy.

Ví dụ: Kiểm tra chuỗi xem trong chuỗi “chào mừng bạn đến với freetuts” có xuất hiện chữ “freetuts” không thì ta viết như sau.

let result = /freetuts/.test("chào mừng bạn đến với freetuts");
alert(result); // True

Kết quả trả về là true vì trong chuỗi trên có xuất hiện chữ freetuts.

3. Ký tự bắt đầu và kết thúc chuỗi RegEx trong javascript

Cấu trúc của một chuỗi luôn có ký tự mở màn và kí tự kết thúc. Và trong RegEx cũng có một số ít ký tự giúp quy ước nơi mở màn chuỗi và nơi kết thúc chuỗi. Cấu trúc của nó sẽ như sau :

/^pattern$/

Trong đó ký tự ^ là khai báo bắt đầu chuỗi, còn $ là khai báo kết thúc chuỗi.

Ký tự bắt đầu chuỗi pattern

Ví dụ: Bạn cần kiểm tra một chuỗi có bắt đầu bằng chữ techtuts hay không?

Giả sử chuỗi cần dò tìm là ” Website techtuts.net là blog công nghệ tiên tiến ” .
Nếu ta giải bài toán này như cách giải ở phần 2 thì chuỗi pattern sẽ như sau :

let result = /techtuts/.test("Website techtuts.net là blog công nghệ");
console.log(result); // True

Rõ ràng kết quả không như ta mong muốn, bởi chữ techtuts không phải là chuỗi bắt đầu. Để giải quyết vấn đề này ta sẽ thêm ký tự ^ đặt đằng trước chuỗi pattern.

let result = /^techtuts/.test("Website techtuts.net là blog công nghệ");
console.log(result); // False

Tóm lại, nếu muốn quy ước tìm từ đầu chuỗi thì bạn sử dụng ký tự ^ nhé.

Ký tự kết thúc chuỗi pattern

Quay lại yêu cầu bài toán trên, ta cần kiểm tra xem chuỗi đó có phải kết thúc bằng chữ techtuts hay không. Ta sẽ thêm dấu $ vào vị trí cuối cùng của chuỗi pattern.

let result = /techtuts$/.test("Website techtuts.net là blog công nghệ");
console.log(result); // False

Kết quả false là đúng mực .

Vậy ta có kết luận như sau: Nếu không khai báo bắt đầu chuỗi hoặc kết thúc chuỗi thì javascript sẽ so khớp tại bất kì vị trí nào bên trong chuỗi, miễn là có xuất hiện giá trị cần tìm.

4. Bảng các biểu thức RegEx trong js căn bản

Trước khi thao tác với những ví dụ thì hãy tìm hiểu thêm bảng tóm tắt dưới đây. Đây là những biểu thức chính quy regular expression cơ bản nhất, được sử dụng nhiều nhất trong lập trình javascript .

Biểu thức Ý nghĩa
[abc] Tìm các chữ cái a,b hoặc c
[0-9] hoăc [a-z] Tìm các ký tự từ 0-9 hoặc từ a-z
(x|y) ìm ký tự x hoặc y
\d Tìm các chữ số
\s Tìm khoảng trắng
n+ Tìm 1 hoặc nhiều chữ n liên tiếp nhau
n* Tìm 0 hoặc nhiều chữ n liên tiếp nhau
n? Tìm 0 hoặc 1 chữ n

Ví dụ 1: Kiểm tra trong chuỗi có xuất hiện chữ Cường hay không?

Ví dụ này ta chỉ cần truyền nguyên chuỗi Cường vào pattern là được .

var patt = /Cường/;
if (patt.test("Tác giả Cường")) {
    document.write('Trong chuỗi có chữ Cường');
}
else {
    document.write('Trong chuỗi không có chữ Cường');
}

Bạn cũng hoàn toàn có thể sử dụng trực tiếp ngay chuỗi pattern như ví dụ sau >

/freetuts/.test("Chào mừng bạn đến với freetuts.net")

Ví dụ 2: Kiểm tra chuỗi có ít nhất một chữ n

Ví dụ này hơi đặc biệt nên ta sử dụng dấu + trong bảng RegEx căn bản trên, nó có tác dụng kiểm tra một chuỗi có ít nhất 1 ký tự cần tìm kiếm.

Demo
RUN

if (/n+/.test("hello")) {
    document.write('Trong chuỗi có chữ n');
}
else {
    document.write('Trong chuỗi không có chữ n');
}

Ví dụ 3: Kiểm tra trong chuỗi có xuất hiện ký tự số hay không?

Với ví dụ này ta có hai cách giải. Cách thứ nhất sử dụng cặp dấu ngoặc [0-9], và cách thứ hai là dùng ký hiệu \d.

Mình sẽ giải bằng cặp dấu ngoặc [0-9].

Demo
RUN

if (/[0-9]/.test("hello123")) {
    document.write('Trong chuỗi có xuất hiện số');
}
else {
    document.write('Trong chuỗi không xuất hiện số');
}

Ví dụ 4: Kiểm tra trong chuỗi không hoặc có xuất hiện số

Bài này ta sẽ kết hợp cặp dấu ngoặc [0-9] và ký hiệu * trong bảng trên. Rõ ràng trường hợp này thì chuỗi RegEx luôn đúng bởi vì ta có 2 trường hợp XUẤT HIỆN hoặc KHÔNG XUẤT HIỆN.

Demo
RUN

if (/[0-9]*/.test("freetuts")) {
    document.write('Luôn luôn chạy');
}
else {
    document.write('Không bao giờ chạy');
}

Ví dụ: Kiểm tra trong chuỗi có chữ H hay không?

Bài này khá đơn thuần là ta chỉ cần truyền chữ H vào như sau :
Demo
RUN

if (/H/.test("hello")) {
    document.write('Có chữ H');
}
else {
    document.write('Không có chữ H');
}

Rõ ràng trong ví dụ có xuất hiện chữ h mà tại sao nó báo không xuất hiện? Lý do là trong chuỗi pattern chúng ta kiểm tra chữ in HOA nhưng trong chuỗi cần kiểm tra thì lại có chữ in thường nên nó trả về false. Để giải quyết thì ta thêm chữ i đằng sau chuỗi pattern.

Demo

RUN

if (/H/i.test("hello")) {
    document.write('Có chữ H');
}
else {
    document.write('Không có chữ H');
}

Các bạn xem phần modifiers ở trên để biết thêm thông tin.

5. Bảng các quy tắc RegEx trong javascript khác

Ở trên mình đã phân phối những quy tắc thường gặp của biểu thức chính quy rồi, thì phần này mình sẽ tổng hợp lại để những bạn thuận tiện ôn tập nhé .

Modifiers

Bảng này gồm 3 ký tự, dùng để khai báo thông số kỹ thuật của chuỗi pattern .

Modifier Description
i So sánh không phân biệt chữ hoa chữ thường (case-insensitive)
g So sánh toàn bộ chuỗi dù trong chuỗi có xuống hàng (global)
m So sánh nhiều dòng (multiline)

Brackets

Bảng những quy tắc tương quan đến dấu ngoặc vuông và ngoặc nhọn .

Expression Description
[abc] Tìm các ký tự a, b hoặc c
[^abc] Tìm các ký tự không phải a, b và c
[0-9] Tìm các ký tự là chữ số từ 0-9
[^0-9] Tìm các ký tự không phải chữ số từ 0-9
(x|y) Tìm ký tự x hoặc y

Metacharacters

Bảng quy tắc những ký tự đơn .

Expression Description
. Tìm ký tự bất kì
\w Tìm ký tự chữ cái
\W Tìm các ký tự không phải là chữ cái
\d Tìm ký tự là chữ số
\D Tìm ký tự không phải là chữ số
\s Tìm ký tự là khoảng trắng
\S Tìm ký tự không phải khoảng trắng
\b Tìm so khớp bắt đầu hoặc kết thúc chuỗi
\B Tìm so khớp không phải khởi đầu hoặc kết thúc chuỗi
\0 Tìm ký tự NULL
\n Tìm ký tự xuống hàng
\t Tìm ký tự tab

Quantifiers

Bảng quy tắc đến số lượng những ký tự .

Expression Description
+ Kiểm tra ký tự xuất hiện một hoặc nhiều lần
* Kiểm tra ký tự xuất hiện không hoặc nhiều lần
? Kiểm tra ký tự xuất hiện không hoặc một lần
{X} Kiểm tra ký tự xuất hiện đúng X lần
{X,Y} Kiểm tra ký tự xuất hiện tối thiểu X lần và tối đa Y lần
{X,} Kiểm tra ký tự xuất hiện ít nhất X lần
^ Kiểm tra ký tự bắt đầu chuỗi
$ Kiểm tra ký tự kết thúc chuỗi

Để lấy hết những ví dụ trên thì bài viết sẽ rất dài, nên phần này mình chỉ làm 4 ví dụ cơ bản thôi nhé. Các bạn hãy thực hành thực tế theo để suy luận và hiểu được ý nghĩa của từng quy tắc .

Ví dụ 1: Kiểm tra chuỗi xuất hiện ít nhất 10 chữ N liên tiếp và không phân biệt chữ hoa chữ thường

Ta sử dụng cú pháp {10,} để kiểm tra ít nhất 10 chữ N liên tiếp.

Demo
RUN

var pattern = /n{10,}/i;
if (pattern.test("10 chu n la nnnnnnnnnn")) {
    document.write('Chuỗi có NHIỀU hơn 10 chữ n');
}
else {
    document.write('Chuỗi có ÍT hơn 10 chữ n');
}

Bài 2: Kiểm tra chuỗi có phải là ‘freetuts.net’ hay không

Để kiểm tra chính xác chuỗi là ‘freetuts.net’ thì bắt buộc ta phải thêm ký tự bắt đầu ^ và kết thúc $ để cố định chuỗi lại.

Ký tự . trong chuỗi ‘freetuts.net’ là ký tự đặc biệt, vì nó có trong danh sách các biểu thức của RegExp nên bắt buộc ta phải thêm dấu \ đằng trước nó.

Demo
RUN

var pattern = /^freetuts\.net$/i;
if (pattern.test("freetuts.net")) {
    document.write('Chuỗi freetuts.net');
}
else {
    document.write('Không phải chuỗi freetuts.net');
}

Bài 3: Kiểm tra chuỗi là các chữ số và dài 8 ký tự

Để kiểm tra các chữ số ta dùng [0-9] và chiều dài 8 ký tự nên ta dùng {8}.

Demo
RUN

var pattern = /^[0-9]{8}$/;
if (pattern.test("12345678")) {
    document.write('Các số dài 8 ký tự');
}
else {
    document.write('Không phải là số hoặc ngắn hơn 8 ký tự');
}

Bài 4: Kiểm tra chuỗi định dạng mã thẻ cào xxxx-xxxx-xxxx-xxxx và x chính là các chữ số.

Ta sử dụng [0-9] để kiểm tra là chữ số. Và các cặp xxxx có chiều dì là 4 nên ta sử dụng {4}.

Demo
RUN

var pattern = /^[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{4}$/;
if (pattern.test("1234-1232-1321-2312")) {
    document.write('Mã thẻ hợp lệ');
}
else {
    document.write('Mã thẻ không hợp lệ');
}

6. Dùng hàm string.match lấy kết quả toàn bộ chuỗi regex

Ngoài phương thức test() ở trên thì Javascript còn một phương thức khác khá hay, đó là là phương thức match() trong đối tượng chuỗi string.

Nếu test() sẽ trả về true nếu so khớp và false nếu không so khớp, thì match() sẽ trả về kết quả dựa vào cấu trúc của chuỗi pattern.

Cú pháp như sau:

string.match(pattern);

Trong đó string là chuỗi cha, còn pattern chình là chuỗi RegEx.

Kết quả hàm này trả về một mảng những giá trị so khớp với chuỗi pattern .

Ví dụ 1: Lấy tất cả các chữ số trong chuỗi “số điện thoại 0979306603”.

let string = "số điện thoại 0979306603";
var result = string.match(/[0-9]+/img);
console.log(result); // ["0979306603"]

// Thử đổi chuỗi string sang giá trị khác
string = "tôi sinh năm 90, vơi tôi sinh năm 92";
result = string.match(/[0-9]+/img);
console.log(result);  // ["90", "92"]

Ví dụ 2: Nếu không tìm thấy thì sẽ trả về giá trị null.

string = "tôi đang học regular expression";
result = string.match(/[0-9]+/img);
console.log(result);  // null

7. Dùng hàm regex.exec lấy kết quả từng group chuỗi RegEx

Hàm string.match() có vẻ hay, nhưng nó không thực sự hữu dụng khi làm việc với những bài toán trong thực tế. Hàm này trả về kết quả là toàn bộ của chuỗi pattern, nên nếu bạn muốn lấy kết quả của một quy tắc trong chuỗi pattern thôi thì làm thế nào? Đừng lo, hàm regex.exec() sẽ giúp bạn xử lý việc này.

Cú pháp của hàm này như sau :

/pattern/.exec(string)

Trong đó, pattern chính là chuỗi biểu thức chính quy, còn string chính là chuỗi cần tìm.

Ví dụ: Viết biểu thức chính quy lấu đường dẫn URL bên trong thẻ img dưới đây.

Nhìn qua cấu trúc chuỗi thì ta sẽ có chuỗi pattern như sau :

//img

Bây giờ ta sẽ thử đặt nó vào hàm exec() xem kết quả như thế nào nhé.

let string = '';
var result = //img.exec(string);
console.log(result); 

Kết quả là một mảng gồm hai thành phần :

regex javascript 1 JPG

Trong đó :

  • Phần tử đầu tiên chính là kết quả của toàn bộ chuỗi pattern //,
  • Phần tử thứ hai là kết quả của quy tắc regex đầu tiên nằm bên trong cặp (), đó chính là (.+).

Để hiểu được ví dụ này thì bạn phải biết khái niệm capturing group trong regular expression.

Capturing group chính là tập hợp những nhóm trong chuỗi pattern. Nhóm đầu tiên là toàn bộ chuỗi, nhóm thứ hai là công thức nằm bên trong cặp () đầu tiên, nhóm thứ ba là công thức nằm bên trong cặp () thứ hai … cứ như vậy cho đến hết chuỗi pattern.

Ví dụ: Chuỗi pattern // sẽ có các group sau:

  1. // – toàn bộ chuỗi.
  2. (. + )- đầu tiên
  3. (. + ) – thứ hai
  4. (.*)

    – thứ ba

Vậy, tác dụng mà hàm exec trả về chính là một mảng, mỗi thành phần trong mảng là một capturing group, trong chuỗi pattern có bao nhiêu group thì nó sẽ trả về bấy nhiêu thành phần .

8. Lời kết

Như vậy là mình đã hướng dẫn xong cách sử dụng biểu thức chính quy RegEx trong javascript. Đây là kiến thức và kỹ năng thuộc dạng khó, nên để hiểu được nó thì bạn phải thực hành thực tế rất nhiều. Vẫn còn khá nhiều phần quan trọng tương quan đến biểu thức chính quy nữa, nhưng vì thời hạn có hạn nên mình sẽ trình diễn ở một bài khác .