Sau khi ngừng hoạt động StackOverflow của ngày hôm qua - việc kết hợp biểu thức chính quy thực sự khó khăn hay việc triển khai đơn giản là không hiệu quả?


8

Hôm qua StackOverflow đã ngừng hoạt động trong nửa giờ. Sau đó, họ đã viết một bài đăng trên blog về nó , chi tiết rằng vấn đề bắt nguồn từ sự phức tạp cao bất ngờ của kết hợp biểu thức chính quy.

Nói tóm lại, biểu thức chính quy a+b, khi chạy trên chuỗi aaaaaaaaaaaaaac, chạy trong thời gian trong đó là số lượng ký tự, vì nó sử dụng quay lui.O(n2)na

Bạn có thể tái tạo sự cố với mã Python sau, trên máy tính của tôi, mất hơn 4 giây để chạy:

import re, time
start = time.time()
re.findall(r'\s+$', ' '*20000 + 'x')
print(time.time() - start)

Điều này rất đáng ngạc nhiên đối với tôi; Tôi đã nghĩ rằng một công cụ đối sánh regex hoạt động hiệu quả hơn, ví dụ: bằng cách xây dựng một DFA từ regex và sau đó chạy chuỗi mong muốn thông qua nó, mà tôi đã nghĩ sẽ là (không bao gồm việc xây dựng DFA).O(n)

(Ví dụ, cuốn sách Giới thiệu về thuật toán của Cormen, Leiserson, Rivest trải qua một thuật toán tương tự trên đường giới thiệu thuật toán Knuth-Morris-Pratt).

Câu hỏi của tôi: Có điều gì đó vốn đã khó khăn trong việc khớp biểu thức chính quy không cho phép thuật toánO(n) hoặc chúng ta chỉ đơn giản nói về việc triển khai không hiệu quả (trong Python, trong bất kỳ điều gì StackOverflow sử dụng, v.v.)?


2
Có một bài viết về điều này. Tôi nghĩ rằng nó ở đây nhưng máy chủ ngừng hoạt động tại thời điểm viết. Tóm tắt điều hành là, vâng, nếu bạn chỉ thực hiện các biểu thức chính quy theo nghĩa đen như nguyên nhân gây ra sự cố ở đây, bạn có thể khớp thời gian tuyến tính bằng cách biên dịch sang máy tự động, đối với các ngôn ngữ được giải thích, bạn cần xem xét thời gian việc biên dịch mất và nếu nó thực sự đáng làm điều đó.
David Richerby

Regex này có thể được viết lại để trở nên nhanh hơn? Tôi có nghĩa là thực sự phải đi xuống các chức năng cơ bản hoặc anh ta chỉ có thể nghĩ lên regex tốt hơn? Tôi đang nói chính xác về điều này / \ s + $ / on ("" * 20000) + "x"
Nakilon

Câu trả lời:


8

Nếu bạn chỉ muốn phân tích các biểu thức chính quy thì bạn sẽ không gặp vấn đề như vậy (trừ khi bạn là một lập trình viên thực sự bất tài, tôi đoán vậy). Hãy cẩn thận bao gồm thời gian cần thiết để xây dựng một máy tự động; một thuật toán tồi tệ hơn không có triệu chứng có thể tốt hơn phương pháp tự động hóa trong nhiều trường hợp trong thực tế.

Vấn đề thực sự là lẽ mà họ sử dụng các chức năng thư viện mà đối phó với regexps đó là cách mạnh hơn so với biểu thức thông thường đơn giản. Ngoài ra, các tính năng như các nhóm phù hợp giới thiệu sự phức tạp hơn nữa.

Trong trường hợp này, sự cố phát sinh do các động cơ này khớp với các chuỗi con (với các biểu thức chính quy đơn giản, chúng tôi thường chỉ khớp toàn bộ đầu vào) và sử dụng quay lui ; trận đấu dài một phần mà cuối cùng không phù hợp gây ra backtracks dài. Về bản chất, đây là trường hợp xấu nhất cho kết hợp chuỗi thời gian ngây thơ, bậc hai.

Điều này có thể được cải thiện? Có lẽ. Sử dụng các ý tưởng từ automata phù hợp với chuỗi, chúng tôi sẽ quay lại không phải là biểu tượng thứ hai, mà là bắt đầu của hậu tố dài nhất khớp với tiền tố của mẫu. Nhưng vì mô hình không còn cố định nữa, nên chắc chắn sẽ không tầm thường để mở rộng ý tưởng.

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.