Biểu thức chính qui
Khái niệm về biểu thức chính qui
Biểu thức chính qui là một khuôn mẫu - một tiêu bản - để đợc sánh với một xâu.
Việc sánh một biểu thức chính qui với một xâu thì hoặc thành công hoặc thất bại. Đôi
khi, sự thành công hay thất bại này có thể là tất cả những gì bạn quan tâm tới. Vào
lúc khác, bạn sẽ muốn lấy một khuôn mẫu đã sánh đúng và thay thế nó bằng một xâu
khác, một phần trong đó có thể phụ thuộc đích xác vào cách thức và nơi chốn mà biểu
thức chính qui đợc sánh đúng.
Biểu thức chính qui thờng đợc nhiều chơng trình UNIX dùng tới, nh grep, sed,
awk, ed, vi, emacs và thậm chí cả nhiều vỏ nữa. mỗi chơng trình đều có một tập các
kí tự tiêu bản khác nhau (phần lớn là chờm lên nhau). Perl là một siêu tệp ngữ nghĩa
cho tất cả những công cụ này - bất kì biểu thức chính qui nào mà có thể đợc viết trong
một trong những công cụ UNIX này thì cũng đều có thể đợc viết trong Perl, nhng
không nhất thiết dùng hệt các kí tự đó.
Cách dùng đơn giản về biểu thức chính qui
Nếu chúng ta tìm tất cả các dòng của một tệp có chứa xâu abc, thì ta có thể dùng
chỉ lệnh grep:
grep abc sonefile > result
Trong trờng hợp này, abc là biểu thức chính qui mà chỉ lệnh grep lấy để kiểm tra
cho từng dòng đa vào. Những dòng sán hđúng sẽ đợc chuyển ra lối ra chuẩn (ở đây,
kết thúc với tệp result vì việc chuyển hớng của vỏ).
Trong Perl, ta có thể nói về xâu abc nh biểu thức chính qui bằng việc bao xâu này
trong hai dấu sổ chéo:
if (/abc/) {
print $_;
}
Nhng cái gì đợc kiểm tra so với biểu thức chính qui abc trong trờng hợp này? Tại
sao, anh bạn cũ của chúng ta, biến $_ lại có mặt ở đây? Khi một biểu thức chính qui
đợc bao trong hai dấu sổ chéo (nh trên), thì biến $_ sẽ đợc kiểm tra theo biểu thức
chính qui đó. Nếu biểu thức chính qui sánh đúng, thì toán tử sánh sẽ cho lại giá trị
đúng. Ngoài ra, nó cho lại giá trị sai.
qui, một sổ chéo, một xâu thay thế, và một sổ chéo cuối cùng, trông tựa nh thế này:
s/ab*c/def/;
Xâu (trong trờng hợp này là biến $_) đợc đem ra đối sánh với biểu thức chính qui
(ab*c). Nếu việc đối sánh thành công, thì phần của xâu sán hđúng sẽ bị loại ra và đợc
thay thế bằng xâu thay thế (def). Nếu việc đối sánh không thành công thì chẳng có gì
xảy ra cả.
Nh với toán tử đối sánh, ta sẽ còn xem xét lại vô số các tuỳ chọn về toán tử thay
thế dới đây, trong mục Thay thế.
Khuôn mẫu
Một biểu thức chính qui là một khuôn mẫu. Một số phần của khuôn mẫu sánh
đúng chỉ các kí tự trong xâu thuộc kiểu đặc biệt. Những phần khác của khuôn mẫu
sánh đúng cho đa kí tự, hay đa đa kí tự. Trớc hết, ta sẽ xem các khuôn mẫu một kí tự,
rồi đến các khuôn mẫu đa kí tự.
Khuôn mẫu một kí tự
Kí tự sánh mẫu đơn giản nhất và thông dụng nhất trong các biểu thức chính qui là
một kí tự sánh với chính nó. Nói cách khác, đặt một chữ a vào trong biểu thức chính
qui đòi hỏi một chữ tơng ứng a trong xâu.
Kí tự sánh mẫu thông dụng nhất tiếp đó là dấu chấm .. Dấu chấm đối sánh bất
kì kí tự riêng lẻ nào ngoại trừ dấu dòng mới (\n). Chẳng hạn, khuôn mẫu /a./ đối sánh
bất kì dãy hai kí tự nào bắt đầu bằng a và không phải là a\n.
Lớp kí tự sánh mẫu đợc biểu diễn bởi cặp dấu ngoặc vuông mở và đóng, và một
danh sách các kí tự nằm giữa hai dấu ngoặc này. Một và chỉ một trong các kí tự này
phải hiện diện tại phần tơng ứng của xâu cần sánh mẫu. Chẳng hạn,
/[abcde]/
sánh với bất kì một trong năm chữ đầu tiên của bảng chữ thờng, trong khi
/[aeiouAEIOU]/
lại sánh với bất kì năm nguyên âm hoặc chữ thờng hoặcchữ hoa. Nếu bạn muốn
đặt dấu ngoặc vuông phải (]) vào danh sách thì hãy đặt một sổ chéo ngợc ở trớc nó,
hay đặt nó nh kí tự đầu tiên bên trong danh sách. Phạm vi của các kí tự (nh a tới z0 có
thể đợc viết tắt bằng việc chỉ ra những điểm cuối của phạm vi đợc tách biệt bởi dấu
[^a-zA-Z0-
9_]
\s
(cách)
[ \r\t\n\f] \S (cách,
không!)
[^ \r\t\n\f]
Khuôn mẫu \d sánh với số. Khuôn mẫu \w sánh với kí tự từ, mặc dầu điều
thực sự sánh đúng là bất kì cái gì hợp lệ trong tên biến Perl. Khuôn mẫu \s sánh với
dấu cách (khoảng trắng), ở đây đợc xác định nh dấu cách, về đầu dòng (không hay
dùng mấy trong UNIX), tab, xuống dòng (dấu dòng mới của UNIX), và kéo giấy. Các
bản chữ hoa sánh đúng với cái đối lập cho những lớp này.
Khuôn mẫu nhóm
Sức mạnh thực sự của biểu thức chính qui là khi bạn có thể nói một hay nhiều
những thứ này hay cho tới năm thứ này. Ta hãy nói về cách thực hiện điều này.
Dãy
Khuôn mẫu nhóm đầu tiên (và có lẽ kém hiển nhiên nhất) là dãy. Điều này có
nghĩa là abc sánh đúng với một a theo sau là b, theo sau là c. Nó dờng nh đơn giản,
nhng tôi cứ đặt tên cho nó để tôi có thể nói về nó sau này.
Bội
Chúng ta đã thấy dấu sao (*) nh một khuôn mẫu nhóm. Dấu sao chỉ ra rằng
không hay nhiều kí tự (hay lớp kí tự) đứng ngay trớc nó.
Hai khuôn mẫu nhóm khác làm việc giống thế là dấu cộng (+), nghĩa là một hay
nhiều kí tự đứng nagy trớc, và dấu hỏi (?), nghĩa là không hay một kí tự ngay trớc.
Chẳng hạn, biểu thức chính qui /fo+ba?r/ sánh đúng cho một f theo sau là một hay
nhiều o, theo sau là a, b và tuỳ chọn a, theo sau là một r.
Trong tất cả ba khuôn mẫu nhóm này, các khuôn mẫu đều tham lam. Nếu một
khuôn mẫu nh vậy có cơ hội sánh đúng giữa năm và mời kí tự thì nó sẽ lọc ra xâu mời
kí tự mỗi lúc. Chẳng hạn:
$_ = fred xxxxxxxxxx barney;
của biểu thức chính qui mà đợc sánh, thì sẽ có đôi chút vấn đề.
Điều gì xảy ra nếu biểu thức xâu và chính qui hơi bị thay đổi đi, chẳng hạn nh:
$_ = a xxx ce xxxxxxx ci xxx d;
/a.*ce.*d/;
Trong trờng hợp này, nếu .* sánh với phần lớn các kí tự có thể trớc c tiếp, thì kí tự
biểu thức chính qui tiếp (e) sẽ không sánh với kí tự tiếp của xâu (i). Trong trờng hợp
này, ta thu đợc việc lần ngợc tự động - số bội bị tháo ra và thử lại, dừng lại tại chỗ
nào đó phía trớc (trong trờng hợp này, tại c trớc, tiếp sau là (e)
*
. Một biểu thức chính
*
*
Về mặt kĩ thuật, có nhiều cách lần ngợc của toán tử * để tìm ra c ở vị trí đầu tiên. Nhng phải hơi thủ thuật hơn để
mô tả nó, mà nó vẫn hoạt động theo cùng nguyên lí.
qui phức tạp có thể bao gồm nhiều mức lần ngợc nh vậy, dẫn tới thời gian thực hiện
lâu.
Dấu ngoặc tròn nh bộ nhớ
Một toán tử nhóm khác là cặp mở và đóng ngoặc tròn quanh bất kì phần khuôn
mẫu nào. Điều này không làm thay đổi liệu khuôn mẫu có sánh đúng hay không, nh-
ng thay vì thế lại làm cho một phần của xâu đợc khuôn mẫu sánh đúng sẽ đợc ghi
nhớ, để cho nó có thể đợc tham khảo tới về sau. Vậy chẳng hạn, (a) vẫn sánh với a,
còn ([a-z]) thì vẫn sánh với bất kì chữ thờng nào.
Để nhớ lại một phần đã ghi nhớ của một xâu, bạn phải đa vào một dáu sổ chéo
ngợc theo sau bởi một số nguyên. Kết cấu khuôn mẫu này biểu thị cho cùng dãy các
kí tự đợc sánh trớc đây trong cặp dấu ngoặc tròn cùng số (đếm từ một) . Chẳng hạn:
/fred(.)barney\1/;
sánh một xâu có chứa fred, tiếp theo là một kí khác dấu dòng mới, tiếp nữa là
barney, rồi tiếp bởi cùng một kí tự đó. Vậy, nó sánh với fredxbarneyx, nhng không
sánh với fredxbarneyy. Bạn hãy so sánh điều đó với:
/fred.barney./