Biểu thức chính quy và 'bắt giữ dấu ngoặc đơn' với 'phản hồi'


7

Chúng tôi biết rằng các biểu thức chính quy (RE) được triển khai với automata hữu hạn (FA). Trong một số ngôn ngữ (như JavaScript) trong RE, có các tính năng như 'nắm bắt dấu ngoặc đơn' với 'phản hồi':

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#special-capturing-parentheses

(x) Kết hợp 'x' và ghi nhớ trận đấu, như ví dụ sau đây cho thấy. Các dấu ngoặc đơn được gọi là dấu ngoặc đơn. '(Foo)' và '(bar)' trong mẫu / (foo) (bar) \ 1 \ 2 / khớp và nhớ hai từ đầu tiên trong chuỗi "foo bar foo bar". \ 1 và \ 2 trong mẫu khớp với hai từ cuối của chuỗi.

Tôi muốn biết liệu mô hình /(foo) (bar) \1 \2/này thực tế là một RE theo định nghĩa của RE mà chúng ta có trong ngôn ngữ chính thức lý thuyết hay nó là một cái gì đó mạnh mẽ hơn. Và nếu đúng như vậy, tôi muốn biết liệu loại tính năng này có được triển khai cùng với FA hay theo một cách khác (theo cách cụ thể nó được triển khai như thế nào).



Xem swtch.com/~rsc/regapi/regapi1.html để biết cách viết tuyệt vời về ý nghĩa hiệu suất trong thế giới thực (mức độ triển khai) của sự khác biệt này. (Chỉnh sửa: Tôi thấy nó đã được liên kết từ câu trả lời này .)
Wildcard

Câu trả lời:


7

RE trong Lý thuyết Automata tương đương với FA, nhưng đối với các ngôn ngữ lập trình (regrec) thì điều này không còn đúng nữa.

Các biểu thức chính quy trong các ngôn ngữ lập trình (như PCRE) mạnh mẽ hơn nhiều so với Biểu thức chính quy (loại 3) trong Lý thuyết tự động.

Dấu ngoặc phù hợp không phải là thông thường cũng như không có ngữ cảnh, đây là một tính năng nhạy với ngữ cảnh. Nhưng RegExp từ câu hỏi không hỗ trợ đầy đủ Loại 2 hoặc Loại 1.

Việc khớp khung không được thực hiện thông qua FA. Trong trường hợp PCRE, nó được thực hiện bằng cách đoán và quay lui.

Hãy xem mô tả của Perl Monks về PCRE .


Cảm ơn bạn. Sau đó, trong trường hợp này, RegExp là một sự lạm dụng ngôn ngữ (chính thức).
ASV

5
Vâng, đó là sự va chạm tên. Ý tưởng ban đầu là một cái gì đó giống như RE, nhưng ngay cả khi nó phát triển, cái tên vẫn còn.
Ác

1
@asv: Trong một thời gian sau khi chụp được giới thiệu RE với các nhóm chụp được gọi là regrec mở rộng hoặc ERE. Sau đó, trong một thời gian sau khi Perl giới thiệu phiên bản RE của họ, nó được gọi là regex để phân biệt nó với regex tiêu chuẩn POSIX và ERE (lưu ý regex so với regrec). Ngày nay mọi người không quan tâm.
slebetman

9

Những khái niệm mở rộng của các biểu thức chính quy nắm bắt nhiều hơn chỉ các ngôn ngữ thông thường. Ví dụ: ([ab]*)\1phù hợp với ngôn ngữ{ww|w{một,b}*}, không thường xuyên và thậm chí không có ngữ cảnh (Ví dụ 2.38 của Sipser, Giới thiệu về Lý thuyết tính toán , ấn bản thứ 3).

Các biểu thức "thông thường" không khớp với các ngôn ngữ thông thường không thể được dịch thành automata hữu hạn, vì automata hữu hạn chỉ khớp với các ngôn ngữ thông thường. Một tác dụng phụ của điều này là nhiều thư viện thậm chí không cố gắng biên dịch thành automata, điều này có thể dẫn đến kết hợp cực kỳ chậm, ngay cả khi biểu thức "chính quy" là biểu thức chính quy thực sự. Russ Cox đã viết một bài báo xuất sắc về điều này, nó cũng đi vào rất nhiều lịch sử.


Cảm ơn bạn cho ví dụ của bạn và cho những thông tin này. :)
ASV

8

Các câu trả lời có thể đang trả lời những gì bạn định hỏi, nhưng không phải là những gì bạn đang hỏi.

Tôi muốn biết liệu mô hình /(foo) (bar) \1 \2/này thực tế là một RE theo định nghĩa của RE mà chúng ta có trong ngôn ngữ chính thức lý thuyết hay nó là một cái gì đó mạnh mẽ hơn. Và nếu đúng như vậy, tôi muốn biết liệu loại tính năng này có được triển khai cùng với FA hay theo một cách khác (theo cách cụ thể nó được triển khai như thế nào).

Trong thực tế, đây một biểu thức chính quy có thể được thực hiện với một máy tự động hữu hạn, bởi vì \1được đảm bảo để đánh giá foo\2được đảm bảo để đánh giá bar.

Do đó, một công cụ regex có thể sử dụng thực tế này để thực sự tạo ra một máy tự động hữu hạn mô tả chính xác ngôn ngữ bạn đề xuất.

Tuy nhiên, nếu bạn thực hiện bất kỳ ảnh chụp nào có điều kiện , thì điều này có thể trở thành sai, như những người khác đã đề cập.

(Lưu ý rằng tôi nói bạn có thể gặp rắc rối, vì một ngôn ngữ như vẫn/(a(aa|aa)|(aa|aa)a)\1\2/ có thể được mô tả qua FA. Tôi chỉ cung cấp cho bạn một điều kiện cần thiết, không phải là một điều kiện đủ. Chỉnh sửa: Điều đó xảy ra với tôi rằng có một điều kiện là không cần thiết cũng không cần thiết đủ, vì cũng có thể biến thành một máy tự động hữu hạn trong khi không thể. Vì vậy, tôi đoán đó chỉ là quy tắc của ngón tay cái.) /(a*)\1//(ab*)\1/


Ok một số mẫu cụ thể với 'bắt ngoặc' có thể là RE. Quan sát tốt.
ASV

@asv: Yup. Ngoài ra, tôi nghĩ một điều khác gây hiểu lầm về tất cả các câu trả lời ở đây (bao gồm cả của tôi) là vấn đề không phải là bắt giữ dấu ngoặc đơn, mà là các phản hồi đề cập đến chúng. Tôi nhớ rằng đọc các dấu ngoặc đơn có thể được xử lý mà không cần quay lại miễn là không có phản hồi. Tuy nhiên, tôi không biết chi tiết đằng sau việc này có thực sự được thực hiện bằng cách sử dụng automata hữu hạn hay không (ấn tượng của tôi là có thể, nhưng tôi không biết chính xác làm thế nào). Nhưng nên có những cách khác để xử lý chúng mà không cần quay lại, chẳng hạn như thông qua phân tích cú pháp LR hoặc một cái gì đó tương tự.
dùng541686

Vâng, câu hỏi là: backreferences
asv

0

Một số triển khai regex nhất định không xây dựng DFA. Ví dụ, triển khai java.util.regex OpenJDK thì không. Kết quả là thời gian khớp của nó chậm hơn so với triển khai được biên dịch DFA như dk.brics.automaton . Tuy nhiên, sau này không hỗ trợ bắt nhóm như là kết quả của việc thực hiện cơ bản.


Hãy nhớ rằng việc xây dựng NFA-> DFA có thể rất tốn kém (2 ^ # nút).
mevets 17/12/18

Ồ vâng, cảm ơn bạn đã chỉ ra điều đó. Tôi đã cập nhật câu trả lời của mình để phản ánh rằng chỉ có thời gian phù hợp với hàm DFA dựa trên là ngắn hơn.
vuamitom 17/12/18
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.