Biểu thức chính quy Regex trong javascript

I. Giới thiệu

Biểu thức chính quy (regular expressions ) là các mẫu dùng để tìm kiếm các bộ kí tự được kết hợp với nhau trong các chuỗi kí tự. Trong JavaScript thì biểu thức chính quy cũng đồng thời là các đối tượng, tức là khi bạn tạo ra một biểu thức chính quy là bạn có một đối tượng tương ứng. Các mẫu này được sử dụng khá nhiều trong JavaScript như phương thức exec và test của RegExp, hay phương thức match, replace, search, và split của String. Ở phạm vi bài viết này, ta cùng tìm hiểu chi tiết hơn về biểu thức chính quy trong JavaScript.

II. Tạo một biểu thức chính quy

Ta có thể tạo biểu thức chính quy theo 2 cách sau:

  • Sử dụng cách mô tả chính quy thuần (regular expression literal):

    var re = /ab+c/;
    

    Các đoạn mã chứa các mô tả chính quy thuần sau khi được nạp vào bộ nhớ sẽ dịch các đoạn mô tả đó thành các biểu thức chính quy. Các biểu thức chính quy được dịch ra này sẽ được coi như các hằng số, tức là không phải tạo lại nhiều lần, điều này giúp cho hiệu năng thực hiện tốt hơn.

  • Tạo một đối tượng RegExp :

    var re = new RegExp("ab+c");
    

    Với cách này, các biểu thức chính quy sẽ được dịch ra lúc thực thi chương trình nên hiệu năng không đạt được như với việc sử dụng cách mô tả chính quy thuần. Nhưng ưu điểm là nó có thể thay đổi được, nên ta thường sử dụng chúng khi ta muốn nó có thể thay đổi được, hoặc khi ta chưa chắc chắn về các mẫu chính quy (pattern) chẳng hạn như khi nhập từ bàn phím.

III. Cách viết một mẫu biểu thức chính quy

Một mẫu biểu thức chính quy là một tập các kí tự thường, như /abc/, hay một tập kết hợp cả kí tự thường và kí tự đặc biệt như /ab*c/ hoặc /Chapter (\d+).\d*/ . Trong ví dụ cuối có chứa cả các dấu ngoặc đơn( () )được sử dụng như các thiết bị nhớ, tức là các mẫu trong phần () này sau khi được tìm kiếm có thể được nhớ lại để sử dụng cho các lần sau.

1. Sử dụng mẫu đơn giản

Các mẫu đơn giản là các mẫu có thể được xây dựng từ các kí tự có thể thể tìm kiếm một cách trực tiếp.

Ví dụ:

mẫu /abc/ sẽ tìm các các đoạn abc theo đúng thứ tự đó trong các chuỗi. Mẫu này sẽ khớp được với "Hi, My name is abc." và "I am from abcdef city.", vì cả 2 chuỗi này đều chứa đoạn 'abc'. Còn với chuỗi Tab tab cc, nó sẽ không khớp vì chuỗi này không chứa abc theo đúng thứ tự, mà chỉ chứa ab c.

2. Sử dụng các kí tự đặc biệt

Các mẫu có thể chứa các kí tự đặc biệt cho các mục đích tìm kiếm nâng cao mà tìm kiếm trực tiếp sẽ khó khăn. Thí dụ như tìm một đoạn chứa một hoặc nhiều hơn một kí tự b, hay tìm một hoặc nhiều kí tự dấu cách (while space).

Ví dụ:

mẫu /ab*c/ có thể tìm các đoạn có chứa: một kí tự 'a', theo sau là không có hoặc có một hoặc có nhiều kí tự 'b', cuối cùng là một kí tự 'c' như chuỗi "cbbabbbbcdebc," sẽ được khớp với xâu con 'abbbbc'.

Bảng dưới đây mô tả đầy đủ các kí tự đặc biệt có thể dùng với biểu thức chính quy.

3. Sử dụng ngoặc tròn

Ngoặc tròn bao quanh bất kỳ phần nào của biểu thức chính quy sẽ khiến phần kết quả so khớp được nhớ. Mỗi lần nhớ, chuỗi con có thể được gọi lại để sử dụng, mô tả trong Using Parenthesized Substring Matches.

Ví dụ:

mẫu /Chapter (\d+).\d*/ khớp đúng với 'Chapter ' theo sau bởi một hoặc nhiều kí tự số, sau nữa là một dấu chấm thập phân, cuối cùng có thể là 0 hoặc nhiều kí tự số. Bên cạnh đó, dấu ngoặc tròn được sử dụng để nhớ một hoặc nhiều kí tự số đầu tiên được khớp.

Mẫu này được tìm thấy trong chuỗi "Open Chapter 4.3, paragraph 6", nhớ '4' nhưng không được tìm thấy trong chuỗi "Chapter 3 and 4", bởi vì chuỗi đó không có dấu chấm sau kí tự số '3'.

Để so khớp một chuỗi con không nhớ, đặt ?: ở vị trí đầu tiên trong ngoặc. Ví dụ, (?:\d+) khớp với một hoặc nhiều kí tự số nhưng không nhớ kết quả so khớp.

IV. Làm việc với biểu thức chính quy

Biểu thức chính quy được sử dụng với phương thức testexec của lớp RegExp hoặc phương thức match, replace, searchsplit của String. Những phương thức này được giải thích chi tiết trong JavaScript Reference.

Như ví dụ dưới đây, phương thức exec được dùng để tìm chuỗi phù hợp theo mẫu so khớp.

var myRe = /d(b+)d/g;
var myArray = myRe.exec("cdbbdbsbz");

Nếu bạn không cần truy cập những thuộc tính khác của biểu thức chính quy, sử dụng cách sau:

var myArray = /d(b+)d/g.exec("cdbbdbsbz");

Nếu bạn muốn khởi tạo một biểu thức chính quy từ một chuỗi:

var myRe = new RegExp("d(b+)d", "g");
var myArray = myRe.exec("cdbbdbsbz");

Với những mã này, so khớp thành công và trả về một mảng kết quả với những thuộc tính được liệt kê trong bảng dưới đây.

Như dạng thứ 2 của ví dụ trên, bạn có thể dùng một biểu thức chính quy được khởi tạo mà không gán nó tới một biến. Tuy nhiên, nếu bạn làm thế, mỗi lần xuất hiện là một biểu thức chính quy mới. Vì lí do này, nếu bạn không gán nó vào một biến, bạn sẽ không thể truy cập các thuộc tính của biểu thức chính quy đó nữa. Ví dụ bạn có đoạn script sau:

var myRe = /d(b+)d/g;
var myArray = myRe.exec("cdbbdbsbz");
console.log("The value of lastIndex is " + myRe.lastIndex);

Kết quả hiển thị là :

The value of lastIndex is 5

Tuy nhiên nếu bạn chạy:

var myArray = /d(b+)d/g.exec("cdbbdbsbz");
console.log("The value of lastIndex is " + /d(b+)d/g.lastIndex);

Thì kết quả hiển thị sẽ là:

The value of lastIndex is 0

Sự xuất hiện của /d(b+)d/g trong 2 lệnh trên là những đối tượng biểu thức chính quy khác nhau và vì thế có những giá trị khác nhau cho thuộc tính lastIndex. Nếu bạn cần truy cập những thuộc tính của một biểu thức chính quy, bạn nên gán nó tới một biến.

Sử dụng nhiều dấu ngoặc tròn

Sử dụng nhiều ngoặc tròn trong một biểu thức chính quy cho ta nhiều kết quả so khớp tương ứng được nhớ. Cho ví dụ, /a(b)c/ khớp với 'abc' và nhớ 'b'. Để gọi lại những kết quả so khớp, sử dụng những phần tử của mảng [1]..., [n].

Số lượng các chuỗi con trong những ngoặc tròn là không giới hạn. Mảng trả về giữ lại tất cả mọi thứ được tìm thấy.

Ví dụ:

Đoạn mã JavaScript dưới đây sử dụng phương thức replace() để giao hoán các từ trong chuỗi. Trong chuỗi thay thế, ta dùng $1$2 để chỉ các chuỗi khớp với mẫu trong ngoặc ở vị trí thứ 1 và 2.

var re = /(\w+)\s(\w+)/;
var str = "John Smith";
var newstr = str.replace(re, "$2, $1");
console.log(newstr);

Kết quả hiển thị là: "Smith, John".

Bài viết được dịch và tham khảo từ đây