Regular Expression trong Javascript
Bài đăng này đã không được cập nhật trong 6 năm
Regular Expression là gì?
Regular Expression (hay còn gọi là Biểu thức chính quy) là một cách để mô tả các pattern (mẫu) trong dữ liệu kiểu chuỗi. Chúng tạo thành một ngôn ngữ nhỏ, riêng biệt là một phần của JavaScript cũng như nhiều ngôn ngữ và công cụ khác. Biểu thức chính quy tuy không đẹp mắt nhưng lại vô cùng hữu ích. Cú pháp của chúng rất là bí ẩn. Nhưng chúng là một công cụ mạnh để kiểm tra và xử lý dữ liệu kiểu chuỗi. Nắm được chúng sẽ giúp cho bạn lập trình một cách hiệu quả hơn.
Cách tạo ra một biểu thức chính quy
Một biểu thức chính quy là một loại đối tượng. Nó có thể được xây dựng với constructor của RegExp hoặc được viết bằng cách kèm theo mẫu trong dấu gạch chéo /
.
var re1 = new RegExp("abc");
var re2 = /abc/;
Với cú pháp thứ hai, mẫu xuất hiện giữa các dấu gạch chéo /
, ta phải xử lý các dấu gạch chéo hơi khác một chút. Thứ nhất, bởi vì dấu gạch chéo /
kết thúc mẫu, chúng ta cần phải đặt dấu gạch chéo \
trước bất kỳ dấu gạch chéo /
nào mà chúng ta muốn nó là một phần của mẫu. Ngoài ra, dấu gạch chéo \
không phải là một phần của mã ký tự đặc biệt (như \n
, \t
, ...) sẽ được bảo toàn, thay vì bị bỏ qua như khi chúng nằm trong chuỗi ở cách 1, và thay đổi ý nghĩa của mẫu. Một số ký tự, chẳng hạn như dấu ?
và dấu +
, có ý nghĩa đặc biệt trong các biểu thức chính quy và phải có dấu gạch chéo \
nếu chúng được dùng để biểu thị cho ký tự.
var eighteenPlus = /eighteen\+/;
Kiểm tra sự trùng khớp
Các đối tượng biểu thức chính quy cũng cung cấp cho chúng ta một số phương thức. Phương thứ đơn giản nhất là test
. Nếu bạn truyền vào một chuỗi, nó sẽ trả về một giá trị Boolean cho bạn biết liệu chuỗi có chứa một trùng khớp của mẫu trong biểu thức.
console.log(/abc/.test("abcde"));
// → true
console.log(/abc/.test("abxde"));
// → false
Một biểu thức chính quy bao gồm các ký tự không đặc trưng thì chỉ đơn giản là đại diện cho chuỗi ký tự đó. Nếu abc
có ở bất cứ nơi nào trong chuỗi mà ta đang kiểm tra (không chỉ ở đầu), kết quả sẽ là true
.
Trùng khớp một tập ký tự
Tìm ra một chuỗi chứa abc
cũng có thể được thực hiện bằng cách gọi đến indexOf
. Các biểu thức chính quy cho phép chúng ta vượt qua điều đó và diễn tả những mẫu phức tạp hơn.
Giả sử chúng ta muốn tìm sự trùng khớp với bất kỳ số nào. Trong một biểu thức chính quy, đặt một tập hợp các ký tự giữa các dấu ngoặc vuông làm phần đó của biểu thức khớp với bất kỳ ký tự nào giữa các dấu ngoặc đó.
Cả hai biểu thức sau đều trùng khớp với tất cả các chuỗi chứa một chữ số:
console.log(/[0123456789]/.test("in 1992"));
// → true
console.log(/[0-9]/.test("in 1992"));
// → true
Trong dấu ngoặc vuông, dấu gạch ngang -
giữa hai ký tự có thể được sử dụng để chỉ một dãy ký tự, trong đó thứ tự được xác định bởi mã Unicode của ký tự. Các ký tự từ 0 đến 9 đứng ngay cạnh nhau theo thứ tự này (mã 48 đến 57), vì vậy [0-9]
bao gồm tất cả các ký tự đó và khớp với bất kỳ chữ số nào.
Có một số nhóm ký tự thông dụng có các cách viết tắt riêng. Các chữ số là một trong số đó: \d
có nghĩa giống như [0-9]
.
Từ viết tắt | Nghĩa |
---|---|
\d |
Bất kỳ ký tự chữ số nào |
\w |
Một ký tự chữ và số và dấu gạch dưới ("ký tự chữ") |
\s |
Bất kỳ ký tự khoảng trắng (khoảng cách, tab, dòng mới và tương tự) |
\D |
Một ký tự mà không phải là chữ số |
\W |
Một ký tự không phải là chữ hoặc số hay dấu gạch dưới |
\S |
Một ký tự không phải khoảng trắng |
. |
Bất kỳ ký tự nào ngoại trừ ký tự xuống dòng |
Để đảo ngược một tập hợp các ký tự - nghĩa là bạn muốn tìm trùng khớp bất kỳ ký tự nào ngoại trừ các ký tự trong tập hợp, bạn có thể viết một ký tự ^
sau dấu ngoặc mở.
var notBinary = /[^01]/;
console.log(notBinary.test("1100100010100110"));
// → false
console.log(notBinary.test("1100100010200110"));
// → true
Lặp lại các phần của một pattern
Bây giờ chúng ta biết làm thế nào để trùng khớp với một chữ số duy nhất. Vậy sẽ ra sao nếu chúng ta muốn khớp một số nguyên - một dãy gồm một hoặc nhiều chữ số?
Khi bạn đặt một dấu cộng +
sau một phần tử trong một biểu thức chính quy, nó cho biết rằng phần tử đó có thể được lặp lại nhiều lần. Như vậy, /\d+/
khớp với một hoặc nhiều ký tự số.
console.log(/'\d+'/.test("'123'"));
// → true
console.log(/'\d+'/.test("''"));
// → false
console.log(/'\d*'/.test("'123'"));
// → true
console.log(/'\d*'/.test("''"));
// → true
Dấu sao *
có ý nghĩa tương tự nhưng cũng cho phép pattern khớp với 0 lần. Bất kỳ cái gì đứng trước dấu sao khi nó không bao giờ có thể ngăn cản một pattern trùng khớp với chuỗi - nó sẽ khớp với 0 lần nếu nó không thể tìm thấy bất kỳ văn bản phù hợp để trùng khớp.
Một dấu chấm hỏi làm cho một phần của một pattern "có thể tùy chọn", có nghĩa là nó có thể xuất hiện 0 hoặc 1 lần. Trong ví dụ sau, ký tự u
được xuất hiện, nhưng pattern cũng khớp khi nó bị thiếu.
var neighbor = /neighbou?r/;
console.log(neighbor.test("neighbour"));
// → true
console.log(neighbor.test("neighbor"));
// → true
Để chỉ ra rằng một pattern nên xuất hiện một số lần chính xác, sử dụng dấu ngoặc nhọn {}
. Ví dụ đặt {4}
sau một phần tử để yêu cầu nó xảy ra chính xác bốn lần. Cũng có thể chỉ định một dải theo cách này: {2,4}
có nghĩa là phần tử phải xuất hiện ít nhất hai lần và nhiều nhất bốn lần.
Gom nhóm các biểu thức phụ
Để sử dụng toán tử như *
hoặc +
trên nhiều phần tử cùng một lúc, bạn có thể sử dụng dấu ngoặc đơn. Một phần của một biểu thức chính quy được cho vào trong dấu ngoặc đơn tính như một phần tử duy nhất cho đến các toán tử sau nó.
var cartoonCrying = /boo+(hoo+)+/i;
console.log(cartoonCrying.test("Boohoooohoohooo"));
// → true
Ký tự dấu +
thứ nhất và thứ hai chỉ áp dụng cho ký tự o
thứ hai trong boo
và hoo
. Dấu +
thứ ba áp dụng cho cả nhóm hoo+
, phù hợp với một hoặc nhiều chuỗi như thế.
Ký tự i
ở cuối của biểu thức trong ví dụ trước làm cho biểu thức chính quy phân biệt hoa thường, cho phép nó khớp với chữ B
in hoa trong chuỗi đầu vào, mặc dù pattern là chữ thường hết.
Các trùng khớp và các nhóm
Phương thức test
là cách đơn giản nhất để kiểm tra trùng khớp với một biểu thức chính quy. Nó chỉ cho bạn biết nó trùng khớp và không có gì khác. Các biểu thức chính quy cũng có một phương thức exec
(thực thi) sẽ trả về null
nếu không tìm thấy sự trùng khớp nào, ngược lại, nó sẽ trả về một đối tượng có thông tin về sự trùng khớp.
var match = /\d+/.exec("one two 100");
console.log(match);
// → ["100"]
console.log(match.index);
// → 8
Một đối tượng được trả về bởi exec
có một thuộc tính index
cho chúng ta biết nơi mà trong chuỗi bắt đầu trùng khớp thành công. Tuy nhiên, đối tượng trông giống như (và thực tế là) một dãy các chuỗi, có phần tử đầu tiên là chuỗi đã khớp - trong ví dụ trước, đây là dãy số mà chúng ta đang tìm kiếm.
Các giá trị chuỗi cũng có một phương thức match
hoạt động giống thế.
console.log("one two 100".match(/\d+/));
// → ["100"]
Khi biểu thức chính quy chứa các biểu thức chính quy phụ được gom nhóm với dấu ngoặc đơn, văn bản khớp với các nhóm đó cũng sẽ hiển thị trong mảng đó. Phần tử đầu tiên luôn là chuỗi khớp với toàn bộ pattern. Phần tử tiếp theo là phần được khớp bởi nhóm đầu tiên (nhóm có dấu mở đầu tiên trong biểu thức), sau đó là nhóm thứ hai, v.v ...
var quotedText = /'([^']*)'/;
console.log(quotedText.exec("she said 'hello'"));
// → ["'hello'", "hello"]
Khi một nhóm không có được sự trùng khớp nào (ví dụ, khi theo sau bởi một dấu hỏi), vị trí của nó trong mảng đầu ra sẽ là undefined
. Tương tự, khi một nhóm được trùng khớp nhiều lần, chỉ có lần trùng khớp cuối cùng xuất hiện trong mảng đó.
console.log(/bad(ly)?/.exec("bad"));
// → ["bad", undefined]
console.log(/(\d)+/.exec("123"));
// → ["123", "3"]
Giới hạn từ và chuỗi
Nếu chúng ta muốn bắt buộc rằng trùng khớp phải kéo dài toàn bộ chuỗi, chúng ta có thể thêm dấu ^
và $
. Dấu ^
khớp với bắt đầu chuỗi đầu vào, trong khi ký hiệu $
khớp với kết thúc chuỗi. Vì vậy, /^\d+$/
khớp một chuỗi chứa toàn bộ một hoặc nhiều chữ số, /^!/
Khớp với bất kỳ chuỗi nào bắt đầu bằng một dấu chấm than !
, và /x^/
không khớp bất kỳ chuỗi nào (không thể có một ký tự x
trước khi bắt đầu chuỗi).
Mặt khác, nếu chúng ta chỉ muốn đảm bảo mẫu bắt đầu và kết thúc trên một ranh giới từ, chúng ta có thể sử dụng dấu \b
. Một ranh giới từ có thể là đầu hoặc cuối của chuỗi hoặc bất kỳ điểm nào trong chuỗi có một ký tự từ (như trong \w
) ở một bên và một ký tự không phải là \w
ở bên kia.
console.log(/cat/.test("concatenate"));
// → true
console.log(/\bcat\b/.test("concatenate"));
// → false
Lưu ý rằng một điểm đánh dấu ranh giới không đại diện cho một ký tự thật sự. Nó chỉ bắt buộc rằng biểu thức chính quy chỉ khớp khi một điều kiện nhất định giữ vị trí mà nó xuất hiện trong mẫu.
Mẫu có chọn lựa
Giả sử chúng ta muốn biết liệu một đoạn văn có chứa không chỉ một chữ số mà là một chữ số theo sau bởi một trong những từ pig
, cow
, hay chicken
, hoặc bất kỳ dạng số nhiều nào của chúng.
Chúng ta có thể viết ba biểu thức chính quy và kiểm tra chúng lần lượt, nhưng có một cách còn hay hơn. Ký tự đường ống |
biểu thị sự lựa chọn giữa mẫu bên trái và mẫu bên phải của nó. Vì vậy, ta có thể dùng như sau:
var animalCount = /\b\d+ (pig|cow|chicken)s?\b/;
console.log(animalCount.test("15 pigs"));
// → true
console.log(animalCount.test("15 pigchickens"));
// → false
Các dấu ngoặc đơn có thể được sử dụng để giới hạn một phần của mẫu mà toán tử |
được áp dụng và bạn có thể đặt nhiều toán tử như vậy cạnh nhau để thể hiện sự lựa chọn giữa nhiều hơn hai mẫu.
Lời kết
Trên đây là những gì mình đã tìm hiểu được về Biểu thức chính quy trong Javascript. Nếu có gì thắc mắc, hãy để lại bình luận và chúng ta sẽ cùng tìm hiểu nhé. Cảm ơn bạn đã quan tâm đến bài viết.
All rights reserved