Brian Kernighan cung cấp một bài viết ngắn trên A Regular Expression Matcher rằng Rob Pike đã viết như một chương trình trình diễn cho một cuốn sách mà họ đang làm việc. Bài viết là một bài đọc rất hay giải thích một chút về mã và các biểu thức thông thường nói chung.
Tôi đã chơi với mã này, thực hiện một vài thay đổi để thử nghiệm với một số tiện ích mở rộng, cũng như trả lại vị trí trong chuỗi phù hợp để chuỗi con khớp với mẫu có thể được sao chép từ văn bản gốc.
Từ bài viết:
Tôi đề nghị với Rob rằng chúng tôi cần phải tìm ra thường xuyên gói biểu hiện nhỏ nhất mà sẽ minh họa cho ý tưởng cơ bản trong khi vẫn nhận một lớp học hữu ích và không tầm thường của các mô hình. Lý tưởng nhất, mã sẽ vừa với một trang.
Rob biến mất vào văn phòng của mình, và ít nhất là tôi nhớ nó ngay bây giờ, xuất hiện lại không quá một hoặc hai giờ với 30 dòng mã C sau đó xuất hiện trong Chương 9 của TPOP. Mã đó triển khai đối sánh cụm từ thông dụng xử lý các cấu trúc này:
c matches any literal character c
. matches any single character
^ matches the beginning of the input string
$ matches the end of the input string
* matches zero or more occurrences of the previous character
Đây là lớp học hữu ích; theo kinh nghiệm của riêng tôi về việc sử dụng các biểu thức thông thường trên cơ sở hàng ngày, nó dễ dàng chiếm 95% của tất cả các trường hợp. Trong nhiều trường hợp, giải quyết vấn đề đúng là bước lớn trên con đường đến một chương trình tuyệt đẹp. Rob xứng đáng nhận được tín dụng tuyệt vời để lựa chọn một cách khôn ngoan, từ trong số nhiều tùy chọn, một số rất nhỏ nhưng vẫn quan trọng, được xác định rõ và có thể mở rộng các tính năng.
Tự thực hiện của Rob là một ví dụ tuyệt vời về mã đẹp: nhỏ gọn, thanh lịch, hiệu quả và hữu ích. Đó là một trong những ví dụ tốt nhất của đệ quy mà tôi đã từng thấy, và nó cho thấy sức mạnh của C con trỏ. Mặc dù tại thời điểm chúng tôi quan tâm nhất đến việc chuyển tải vai trò quan trọng của một ký hiệu tốt trong việc giúp chương trình dễ sử dụng hơn và dễ viết hơn, mã biểu thức chính quy cũng là một cách tuyệt vời để minh họa thuật toán, dữ liệu cấu trúc, kiểm tra, tăng cường hiệu suất và các chủ đề quan trọng khác .
Mã nguồn C thực tế từ bài viết rất hay.
/* match: search for regexp anywhere in text */
int match(char *regexp, char *text)
{
if (regexp[0] == '^')
return matchhere(regexp+1, text);
do { /* must look even if string is empty */
if (matchhere(regexp, text))
return 1;
} while (*text++ != '\0');
return 0;
}
/* matchhere: search for regexp at beginning of text */
int matchhere(char *regexp, char *text)
{
if (regexp[0] == '\0')
return 1;
if (regexp[1] == '*')
return matchstar(regexp[0], regexp+2, text);
if (regexp[0] == '$' && regexp[1] == '\0')
return *text == '\0';
if (*text!='\0' && (regexp[0]=='.' || regexp[0]==*text))
return matchhere(regexp+1, text+1);
return 0;
}
/* matchstar: search for c*regexp at beginning of text */
int matchstar(int c, char *regexp, char *text)
{
do { /* a * matches zero or more instances */
if (matchhere(regexp, text))
return 1;
} while (*text != '\0' && (*text++ == c || c == '.'));
return 0;
}
Có ngoặc trong regex của bạn hoặc là * và? chỉ áp dụng cho các ký tự đơn? –
@ A.Rex, không có dấu ngoặc đơn.the * và? có cùng nghĩa như được định nghĩa bởi regex – Tracy
@Tracy: Có rất nhiều cách diễn giải và triển khai khác nhau của các đối sánh cụm từ thông dụng và chúng không hoạt động giống hệt nhau. Điều quan trọng là bạn hiểu được những giải thích nào có nghĩa là, để trả lời câu hỏi này một cách chính xác. –