Làm thế nào để biểu thức chính quy thực sự làm việc?


30

Nói rằng bạn có một tài liệu với một bài luận được viết. Bạn muốn phân tích bài luận này để chỉ chọn một số từ nhất định. Mát mẻ.

Là sử dụng một biểu thức chính quy nhanh hơn phân tích cú pháp dòng tệp theo từng dòng và từng chữ để tìm kiếm sự trùng khớp? Nếu vậy, làm thế nào nó hoạt động? Làm thế nào bạn có thể đi nhanh hơn là nhìn vào từng từ?


5
Bạn cho rằng (ngụ ý bằng chứng bằng không) rằng một biểu thức chính quy sẽ nhanh hơn nhưng bạn không biết tại sao lại như vậy? Có lẽ bạn nên xem xét lại giả định của mình sau đó.
pdr

3
do đó, giả định. Nếu tôi có bằng chứng, nó sẽ không phải là một, phải không?
lazeR

4
Đó không phải là vấn đề. Vấn đề là điều gì dẫn bạn đến giả định đó ... Bạn không cần bằng chứng cho câu hỏi của mình, nhưng bạn cần lý luận cho những giả định của mình.
yannis

1
ồ, không phải mọi ký tự của chuỗi đầu vào chỉ chuyển một máy trạng thái sang trạng thái tiếp theo. Tôi không thấy bất cứ ai có thể khiến hoạt động đó chậm lại ...
tp1

2
Tôi không chắc chắn về việc nhanh hơn, nhưng lý do chính của tôi để sử dụng các biểu thức thông thường là do sự thanh lịch của các mẫu khớp phức tạp, đơn giản là bạn sẽ không tìm thấy cách nào tốt hơn để diễn đạt nó trong môi trường mã hóa.
Mantorok

Câu trả lời:


47

Làm thế nào nó hoạt động?

Hãy xem lý thuyết automata

Nói tóm lại, mỗi biểu thức chính quy có một máy tự động hữu hạn tương đương và có thể được biên dịch và tối ưu hóa thành máy tự động hữu hạn. Các thuật toán liên quan có thể được tìm thấy trong nhiều sách biên dịch. Các thuật toán này được sử dụng bởi các chương trình unix như awk và grep.

Tuy nhiên, hầu hết các ngôn ngữ lập trình hiện đại (Perl, Python, Ruby, Java (và các ngôn ngữ dựa trên JVM), C #) không sử dụng phương pháp này. Họ sử dụng một cách tiếp cận quay lui đệ quy, trong đó biên dịch một biểu thức chính quy thành một cây hoặc một chuỗi các cấu trúc đại diện cho các phần phụ khác nhau của biểu thức chính quy. Hầu hết các cú pháp "biểu thức chính quy" hiện đại cung cấp các phản hồi nằm ngoài nhóm ngôn ngữ thông thường (chúng không có đại diện trong automata hữu hạn), có thể thực hiện được trong phương pháp quay lui đệ quy.

Việc tối ưu hóa thường mang lại một máy trạng thái hiệu quả hơn. Ví dụ: xem xét aaaab | aaaac | aaaad, một lập trình viên bình thường có thể thực hiện tìm kiếm đơn giản nhưng kém hiệu quả (so sánh ba chuỗi riêng biệt) ngay trong mười phút; nhưng nhận ra nó tương đương với aaaa [bcd], một tìm kiếm tốt hơn có thể được thực hiện bằng cách tìm kiếm bốn 'a' đầu tiên sau đó kiểm tra ký tự thứ 5 dựa vào [b, c, d]. Quá trình tối ưu hóa là một trong những công việc biên dịch tại nhà của tôi nhiều năm trước, vì vậy tôi cho rằng nó cũng có trong hầu hết các công cụ biểu thức chính quy hiện đại.

Mặt khác, các máy trạng thái có một số lợi thế khi chúng chấp nhận các chuỗi vì chúng sử dụng nhiều không gian hơn so với "triển khai tầm thường". Hãy xem xét một chương trình để bỏ dấu ngoặc kép trên các chuỗi SQL, nghĩa là: 1) bắt đầu và kết thúc bằng các dấu ngoặc đơn; 2) dấu ngoặc kép đơn được thoát bằng hai trích dẫn đơn liên tiếp. Vì vậy: đầu vào ['a' ''] sẽ mang lại đầu ra [a ']. Với một máy trạng thái, các dấu ngoặc kép đơn liên tiếp được xử lý bởi hai trạng thái. Hai trạng thái này phục vụ mục đích ghi nhớ lịch sử đầu vào sao cho mỗi ký tự đầu vào được xử lý chính xác chỉ một lần, như minh họa sau:

...
S1->'->S2
S1->*->S1, output *, * can be any other character 
S2->'->S1, output '
S2->*->END, end the current string

Vì vậy, theo tôi, biểu thức chính quy có thể chậm hơn trong một số trường hợp tầm thường, nhưng thường nhanh hơn thuật toán tìm kiếm thủ công, do thực tế là việc tối ưu hóa có thể được thực hiện một cách đáng tin cậy bởi con người.

(Ngay cả trong các trường hợp tầm thường như tìm kiếm chuỗi, một công cụ thông minh có thể nhận ra đường dẫn duy nhất trong bản đồ trạng thái và giảm phần đó thành so sánh chuỗi đơn giản và tránh quản lý trạng thái.)

Một công cụ cụ thể từ khung / thư viện có thể chậm vì công cụ này thực hiện một loạt các thứ khác mà lập trình viên thường không cần. Ví dụ: lớp Regex trong .NET tạo ra một loạt các đối tượng bao gồm Khớp, Nhóm và Chụp.


2
Tôi không thể nói nó tốt hơn bản thân mình. Điều duy nhất tôi muốn thêm: Biểu thức chính quy cũng có thể bù đắp cho các lập trình viên lười biếng. Trong ví dụ bạn đề cập aaaab|aaaac|aaaadso với aaaa[bcd]. Điều đáng nói là cả hai đều tương đương về mặt toán học và tạo ra cùng một DFA, do đó giúp các lập trình viên có nhiều tự do hơn để biểu diễn một biểu thức chính quy theo cách có ý nghĩa (không phải đây là cách làm thông thường, nhưng ... bạn biết). ..
riwalk

Cảm ơn, điều này thực sự có ý nghĩa nhờ vào lớp automata mà tôi đã tham gia
lazeR

Đây có phải là một ví dụ về một vấn đề tầm thường nơi regex là overkill ?: stackoverflow.com/questions/18955099/...
Menelaos Bakopoulos

17

Biểu thức thông thường chỉ nhìn nhanh vì bạn có máy tính nhanh.

Quay trở lại những năm 1980 khi 1 MIPS là một máy tính nhanh, các biểu thức chính quy là một lĩnh vực khá lo lắng, quan tâm và nghiên cứu vì chúng chậm, xấu và tính toán chuyên sâu. Phát triển thuật toán thông minh theo sau và giúp đỡ - nhưng với tất cả các mục đích thực tế ngày nay, bạn đang thấy phép màu của những cỗ máy nhanh chóng vượt qua các vết nứt.


2
Nếu bạn chỉ tìm kiếm một từ duy nhất thì cả hai phương thức đều giống nhau (hoặc regrec chậm hơn một chút). Nhưng với một biểu thức phức tạp (và văn bản có kích thước hợp lý), biểu thức thông thường có thể sẽ nhanh hơn một tìm kiếm đơn giản (giả sử bạn viết tìm kiếm đơn giản (bạn luôn có thể viết một tìm kiếm phức tạp nhanh như vậy)). Bây giờ thời tiết rất quan trọng là một câu hỏi quá chung chung và bạn sẽ phải xem xét nó trong từng trường hợp.
Martin York

3
-1. Lý thuyết về biểu thức chính quy có từ những năm 50 và là công cụ tạo ra các máy phân tích từ vựng (và bằng cách mở rộng, trình biên dịch). Họ tạo ra các máy trạng thái rất hiệu quả (có thể chứng minh) sử dụng số lượng trạng thái ít nhất có thể. Các máy trạng thái kết quả có thể khớp các mẫu phức tạp nhanh hơn nhiều so với bất cứ thứ gì bạn có thể viết bằng tay. Họ nhìn nhanh vì họ nhanh.
riwalk

Có thể đã bỏ lỡ quan điểm của tôi một chút. Họ có thể "nhanh" nhưng tất cả đều tương đối - vẫn còn rất nhiều việc phải làm. Một số câu trả lời khác ở đây cũng chịu đọc.
quick_now

Câu trả lời này có liên quan đến câu hỏi không? và 13 upvote như thế nào?
Sadanand

7

Tại sao bạn nghĩ rằng họ nhanh hơn tìm kiếm tài liệu?

Có một số thủ thuật bạn có thể làm, ví dụ. nếu bạn đang tìm kiếm một từ 10 bản bắt đầu bằng A và kết thúc bằng B thì nếu bạn tìm thấy vị trí A và ký tự 9 trên không phải là B thì bạn có thể bỏ qua một số. xem thuật toán Knuth của Morris Morris Pratt


5

Điều gì làm cho một biểu thức thường xuyên nhanh chóng?

Thật ra, họ không như vậy. Không nhiều. Chỉ là chúng không đủ chậm để hầu hết chúng ta chú ý. Trở lại trong 'những ngày chậm chạp cũ, nó đáng chú ý hơn nhiều.

Chúng cũng không phải là công cụ phù hợp cho mọi công việc - búa .


+1 Cảm ơn đã nhắc nhở tôi về tác phẩm nghệ thuật đặc biệt đó ...
yannis

5

Các mã của RegEx tương đối nhanh hơn để viết mã bởi vì hầu hết các thư viện là kết quả của việc nhiều nhà phát triển dành nhiều năm để tối ưu hóa chúng để giảm bớt mọi hiệu suất cuối cùng có thể. Thật khó cho một cá nhân duy nhất sao chép mã đó trong mã tìm kiếm của riêng họ.


4
s / rít / bóp /?
Péter Török

4

Tiền đề cơ bản của bạn là sai.

Biểu thức thông thường không phải lúc nào cũng nhanh hơn một tìm kiếm đơn giản. Tất cả phụ thuộc vào bối cảnh. Nó phụ thuộc vào độ phức tạp của biểu thức, độ dài của tài liệu được tìm kiếm và một loạt các yếu tố.

Điều gì xảy ra là biểu thức chính quy sẽ được biên dịch thành một trình phân tích cú pháp đơn giản (cần có thời gian). Do đó, nếu tài liệu nhỏ, thời gian thêm này sẽ vượt trội hơn bất kỳ lợi thế nào. Ngoài ra, nếu biểu thức đơn giản, thì biểu thức chính quy sẽ không cung cấp cho bạn bất kỳ lợi thế nào.

Nếu biểu thức phức tạp và tài liệu đủ lớn, thì bạn có thể đạt được một số lợi ích. Việc điều này có đủ ý nghĩa để coi các biểu thức thông thường nhanh hơn hay không sẽ phụ thuộc rất nhiều vào mức độ bạn muốn đưa vào tìm kiếm (cũng như các biểu thức thông thường có thể có một số tối ưu hóa mà thư viện có thể cung cấp mà bạn không nghĩ đến mình).

Những gì tôi đang cố gắng nói là không có câu trả lời chung chung. Nếu bạn có một biểu thức cụ thể (và kích thước tài liệu đã biết), thì bạn có thể nói rút ra câu trả lời có / không về việc liệu biểu thức sẽ nhanh hơn tìm kiếm đơn giản (và tại sao).

Ưu điểm thực sự của biểu thức chính quy là một khi bạn hiểu cách viết chúng, khả năng diễn đạt một tìm kiếm phức tạp một cách súc tích. Vì nó là một hình thức tổng quát, sau đó bạn có thể xây dựng các công cụ cho phép tìm kiếm theo cách hữu ích trong trường hợp chung; nó thường ít nhất là nhanh như một tìm kiếm đơn giản (trên các tài liệu có kích thước tối thiểu; trên các tài liệu nhỏ hơn mức này không thành vấn đề vì ngay cả khi chậm hơn, nó vẫn đủ nhanh).


1

Điều hợp lý là trong một số ngôn ngữ cấp cao (có thể là javascript), sử dụng thư viện regex được triển khai bằng ngôn ngữ cấp thấp (có lẽ là C) sẽ nhanh hơn viết logic trình phân tích cú pháp bằng ngôn ngữ cấp cao.

Hợp lý - Tôi không biết nếu điều này thực sự xảy ra.


Đẹp quá Đó là điều tôi cũng đã xem xét. Nhưng với bộ xử lý ngày nay nhanh hơn so với người tiền nhiệm của nó, tôi có thể nói một cách an toàn nếu bạn viết mã hiệu quả, bạn sẽ hiếm khi có thể nói khác biệt. Tôi thực sự trên toàn bộ không thực sự gaga trên toàn bộ giả thuyết biểu hiện nhanh hơn thường xuyên! ;-)
dùng3833732
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.