Câu trả lời:
Phần quan trọng nhất là các khái niệm. Khi bạn hiểu cách các khối xây dựng hoạt động, sự khác biệt về số lượng cú pháp ít hơn nhiều so với phương ngữ nhẹ. Một lớp trên cú pháp của công cụ biểu thức chính quy của bạn là cú pháp của ngôn ngữ lập trình bạn đang sử dụng. Các ngôn ngữ như Perl loại bỏ hầu hết các biến chứng này, nhưng bạn sẽ phải ghi nhớ các cân nhắc khác nếu bạn đang sử dụng các biểu thức thông thường trong chương trình C.
Nếu bạn nghĩ các biểu thức thông thường là các khối xây dựng mà bạn có thể trộn và khớp theo ý muốn, nó sẽ giúp bạn học cách viết và gỡ lỗi các mẫu của riêng bạn mà còn cách hiểu các mẫu được viết bởi người khác.
Về mặt khái niệm, các biểu thức chính quy đơn giản nhất là các ký tự theo nghĩa đen. Mẫu N
phù hợp với ký tự 'N'.
Biểu thức chính quy bên cạnh trình tự khớp nhau. Ví dụ: mẫuNick
khớp với chuỗi 'N', theo sau là 'i', theo sau là 'c', theo sau là 'k'.
Nếu bạn đã từng sử dụng grep
trên Unix Unix ngay cả khi chỉ để tìm kiếm các chuỗi tìm kiếm thông thường thì bạn đã sử dụng các biểu thức thông thường! (The re
trong grep
đề cập đến biểu thức thông thường.)
Thêm một chút phức tạp, bạn có thể ghép 'Nick' hoặc 'nick' với mẫu [Nn]ick
. Phần trong ngoặc vuông là một lớp ký tự , có nghĩa là nó khớp chính xác với một trong các ký tự được đính kèm. Bạn cũng có thể sử dụng phạm vi trong các lớp nhân vật, vì vậy[a-c]
khớp với 'a' hoặc 'b' hoặc 'c'.
Các mô hình .
rất đặc biệt: thay vì phù hợp với một dấu chấm đen duy nhất, nó phù hợp với bất kỳ nhân vật † . Về mặt khái niệm, nó giống như lớp nhân vật thực sự lớn[-.?+%$A-Za-z0-9...]
.
Hãy nghĩ về các lớp nhân vật như các menu: chỉ chọn một.
Sử dụng .
có thể giúp bạn tiết kiệm rất nhiều cách gõ và có các phím tắt khác cho các mẫu phổ biến. Nói rằng bạn muốn khớp một chữ số: một cách để viết đó là [0-9]
. Chữ số là mục tiêu phù hợp thường xuyên, vì vậy bạn có thể sử dụng phím tắt \d
. Những người khác là \s
(khoảng trắng) và \w
(ký tự từ: chữ và số gạch dưới).
Các biến thể trên là phần bổ sung của chúng, vì vậy, \S
phù hợp với bất kỳ ký tự không phải khoảng trắng nào, chẳng hạn.
Từ đó, bạn có thể lặp lại các phần của mẫu bằng các bộ định lượng . Ví dụ: mẫu ab?c
khớp với 'abc' hoặc 'ac' vì bộ ?
định lượng làm cho mẫu con mà nó sửa đổi tùy chọn. Các định lượng khác là
*
(không hoặc nhiều lần hơn)+
(một hoặc nhiều lần){n}
(chính xác là n lần){n,}
(ít nhất n lần){n,m}
(ít nhất n lần nhưng không quá m lần)Đặt một số các khối này lại với nhau, mô hình [Nn]*ick
khớp với tất cả
Trận đấu đầu tiên thể hiện một bài học quan trọng: *
luôn thành công!Bất kỳ mô hình có thể phù hợp với số lần không.
Một vài ví dụ hữu ích khác:
[0-9]+
(và tương đương với nó \d+
) phù hợp với bất kỳ số nguyên không âm nào\d{4}-\d{2}-\d{2}
phù hợp với các ngày được định dạng như 2019-01-01Một bộ định lượng sửa đổi mô hình ở bên trái ngay lập tức của nó. Bạn có thể mong đợi 0abc+0
khớp với '0abc0', '0abcabc0', v.v., nhưng mẫu ngay lập tức ở bên trái của bộ định lượng cộng là c
. Điều này có nghĩa 0abc+0
phù hợp với '0abc0', '0abcc0', '0abccc0', v.v.
Để khớp một hoặc nhiều chuỗi 'abc' với các số 0 ở hai đầu, hãy sử dụng 0(abc)+0
. Các dấu ngoặc đơn biểu thị một mẫu con có thể được định lượng dưới dạng một đơn vị. Nó cũng phổ biến đối với các công cụ biểu thức chính quy để lưu hoặc "bắt" phần văn bản đầu vào khớp với nhóm được ngoặc đơn. Trích xuất bit theo cách này linh hoạt hơn và ít bị lỗi hơn so với đếm các chỉ số vàsubstr
.
Trước đó, chúng tôi đã thấy một cách để khớp với 'Nick' hoặc 'nick'. Khác là với xen kẽ như trong Nick|nick
. Hãy nhớ rằng sự xen kẽ bao gồm mọi thứ ở bên trái và mọi thứ ở bên phải của nó. Sử dụng dấu ngoặc đơn để nhóm các giới hạn phạm vi |
, ví dụ như , (Nick|nick)
.
Ví dụ khác, bạn có thể viết tương đương [a-c]
như a|b|c
, nhưng điều này có thể sẽ không tối ưu vì việc triển khai nhiều giải pháp thay thế giả định sẽ có độ dài lớn hơn 1.
Mặc dù một số nhân vật phù hợp với chính họ, những người khác có ý nghĩa đặc biệt. Mẫu \d+
không khớp với dấu gạch chéo ngược theo sau chữ thường D theo sau là dấu cộng: để có được điều đó, chúng tôi sẽ sử dụng \\d\+
. Dấu gạch chéo ngược loại bỏ ý nghĩa đặc biệt từ ký tự sau.
Định lượng biểu thức chính quy là tham lam. Điều này có nghĩa là chúng khớp với càng nhiều văn bản càng tốt trong khi cho phép toàn bộ mẫu khớp với nhau thành công.
Ví dụ: giả sử đầu vào là
"Xin chào," cô nói, "Bạn có khỏe không?"
Bạn có thể mong đợi ".+"
chỉ khớp với 'Xin chào', và sau đó sẽ ngạc nhiên khi bạn thấy rằng nó khớp với 'Xin chào' suốt từ 'bạn?'.
Để chuyển từ tham lam sang những gì bạn có thể nghĩ là thận trọng, hãy thêm một phần bổ sung ?
vào bộ định lượng. Bây giờ bạn hiểu làm thế nào \((.+?)\)
, ví dụ từ câu hỏi của bạn hoạt động. Nó khớp với chuỗi của dấu ngoặc đơn bên trái, theo sau là một hoặc nhiều ký tự và được kết thúc bằng dấu ngoặc đơn bên phải.
Nếu đầu vào của bạn là '(123) (456)', thì lần chụp đầu tiên sẽ là '123'. Các bộ lượng hóa không tham lam muốn cho phép phần còn lại của mẫu bắt đầu khớp càng sớm càng tốt.
(Đối với sự nhầm lẫn của bạn, tôi không biết bất kỳ phương ngữ biểu thức chính quy ((.+?))
nào sẽ làm điều tương tự. Tôi nghi ngờ có gì đó bị mất khi truyền đi đâu đó trên đường đi.)
Sử dụng mẫu đặc biệt ^
để chỉ khớp ở đầu đầu vào của bạn và $
chỉ khớp với ở cuối. Tạo "bookends" với các mẫu của bạn trong đó bạn nói, "Tôi biết những gì ở phía trước và phía sau, nhưng cho tôi mọi thứ ở giữa" là một kỹ thuật hữu ích.
Nói rằng bạn muốn khớp với các bình luận của mẫu
-- This is a comment --
bạn sẽ viết ^--\s+(.+)\s+--$
.
Biểu thức thông thường là đệ quy, vì vậy bây giờ bạn đã hiểu các quy tắc cơ bản này, bạn có thể kết hợp chúng theo cách bạn muốn.
: Tuyên bố trên .
phù hợp với bất kỳ nhân vật nào là sự đơn giản hóa cho các mục đích sư phạm không hoàn toàn đúng. Dot phù hợp với bất kỳ nhân vật nào ngoại trừ dòng mới, "\n"
nhưng trong thực tế, bạn hiếm khi mong đợi một mẫu như .+
vượt qua ranh giới dòng mới. Các biểu thức Perl có một /s
công tắc và Java Pattern.DOTALL
, ví dụ, để làm cho .
phù hợp với bất kỳ ký tự nào. Đối với các ngôn ngữ không có tính năng như vậy, bạn có thể sử dụng một cái gì đó như [\s\S]
để khớp với "bất kỳ khoảng trắng hoặc bất kỳ khoảng trắng nào", nói cách khác là bất cứ điều gì.
a{,m}
không phải là một thứ, ít nhất là trong Javascript, Perl và Python.