2009-04-11 24 views
8

Tôi đã gặp sự cố trong Regexes để chia mã thành các thành phần chức năng. Họ có thể phá vỡ hoặc có thể mất một thời gian dài để họ kết thúc. Trải nghiệm đặt ra một câu hỏi:Khi nào tôi nên sử dụng trình phân tích cú pháp?

"Khi nào tôi nên sử dụng trình phân tích cú pháp?"

+0

Không chính xác chắc chắn nếu đó là bản sao - nhưng hãy kiểm tra các bài đăng sau đây: * [Khi nào là một vấn đề quá phức tạp cho một biểu thức chính quy?] (Http: // stackoverflow.com/questions/230517/khi-là-một-vấn đề-quá phức tạp-cho-một-regular-expression) * [Giải pháp thay thế cho biểu thức chính quy] (http://stackoverflow.com/questions/514313/alternatives-to biểu thức không đều) – dirkgently

Trả lời

9

Bạn nên sử dụng trình phân tích cú pháp khi bạn quan tâm đến ý nghĩa từ ngữ hoặc ngữ nghĩa từ vựng hoặc ngữ nghĩa của văn bản, khi các mẫu có thể thay đổi. Phân tích cú pháp thường quá mức cần thiết khi bạn chỉ đơn giản là tìm kiếm khớp hoặc thay thế mẫu ký tự, bất kể ý nghĩa chức năng của chúng.

Trong trường hợp của bạn, bạn có vẻ quan tâm đến ý nghĩa đằng sau văn bản ("thành phần chức năng" của mã), do đó, trình phân tích cú pháp sẽ là lựa chọn tốt hơn. Tuy nhiên, các trình phân tích cú pháp có thể sử dụng regex trong nội bộ, vì vậy chúng không nên được coi là loại trừ lẫn nhau.


Tuy nhiên, trình phân tích cú pháp "" không tự động có nghĩa là nó phức tạp. Ví dụ: nếu bạn quan tâm đến các khối mã C, bạn có thể phân tích cú pháp các nhóm lồng nhau của {và}. Trình phân tích cú pháp này sẽ chỉ quan tâm đến hai thẻ ('{' và '}') và các khối văn bản giữa chúng.

Tuy nhiên, so sánh regex đơn giản không đủ ở đây do ngữ nghĩa lồng nhau. Hãy lấy đoạn mã sau:

void Foo(bool Bar) 
{ 
    if(Bar) 
    { 
     f(); 
    } 
    else 
    { 
     g(); 
    } 
} 

Trình phân tích cú pháp sẽ hiểu phạm vi tổng thể của Foo, cũng như mỗi phạm vi bên trong chứa trong Foo (nếu và khối khác). Khi nó gặp phải mỗi '' token, nó "hiểu" ý nghĩa của chúng. Một tìm kiếm đơn giản, tuy nhiên không hiểu được ý nghĩa đằng sau những văn bản và có thể giải thích sau đây để trở thành một khối, mà chúng tôi đương nhiên biết là không đúng:

{ 
    if(Bar) 
    { 
     f(); 
    } 
0

Câu hỏi của bạn là một chút mơ hồ, nhưng tôi đoán tôi ý kiến ​​là khi regex của bạn trở nên phức tạp hoặc mất quá nhiều thời gian và bạn có một "ngôn ngữ" được xác định hợp lý để giải quyết, trình phân tích cú pháp sẽ dễ dàng hơn.

Tôi không nghĩ rằng bạn có thể đặt một đường trong cát và nói rằng bất cứ điều gì ở một bên có thể được thực hiện bởi regex, và ở phía bên kia bạn cần một trình phân tích cú pháp. Nó phụ thuộc vào tình hình.

1

Bạn cần sử dụng trình phân tích cú pháp ngay sau khi bạn gặp sự cố biểu thức chính quy không có nghĩa là, (hoặc chỉ đơn giản là không thể) giải quyết. Ví dụ, dấu ngoặc đơn cân bằng (un) là một trong những vấn đề đó. Mặc dù một số hương vị, như PCRE, giúp bạn đi xa đến mức họ không thể thắng được một trình phân tích cú pháp bằng văn bản.

2

Có một vài trường hợp sử dụng hấp dẫn cho trình phân tích cú pháp trên biểu thức chính quy. Bạn nên sử dụng trình phân tích cú pháp thay vì cụm từ thông dụng:

  • Bất cứ khi nào các loại biểu thức bạn muốn làm việc phức tạp hơn nhiều thực thể ngữ nghĩa (thẻ, biến, số điện thoại, v.v.).
  • Bất cứ khi nào bạn cần biết ý nghĩa ngữ nghĩa của văn bản thay vì chỉ phù hợp với mẫu. Ví dụ, nếu bạn đang cố gắng để phù hợp với tất cả các cách có thể viết một số điện thoại, một phân tích cú pháp có lẽ là tốt hơn so với một regex. Nếu bạn đang cố gắng để phù hợp với một mô hình cụ thể xảy ra tương ứng với một số điện thoại, một regex có lẽ là tốt.
  • Bất cứ khi nào đầu vào không thể đảm bảo được tạo đúng.
  • Nếu bạn đang làm việc hoàn toàn trong cấu trúc của một ngôn ngữ được xác định rõ ràng có đặc tả cú pháp (C#, XML, C++, Ruby, v.v.), đã có một trình phân tích cú pháp, do đó bạn đã hoàn thành công việc cho bạn.
+0

+1 cho các ví dụ cụ thể. –

+0

@John Feminella, tôi có thể sai, nhưng tôi không chắc chắn tôi đồng ý với ví dụ về số điện thoại. Nếu chúng ta muốn kết hợp nhiều cách khác nhau để viết một số điện thoại, tôi nghĩ rằng nó vẫn có thể được biểu diễn rất tốt như một regex (với một danh sách tùy chọn các mẫu). Đây có thể không phải là một ví dụ rất tốt về một trường hợp khi ngữ nghĩa là cần thiết. – Parag

+0

@Parag: Tôi ước gì tôi vẫn có được sự bình an nội tâm hạnh phúc đến từ những con số tin tưởng có thể được kết hợp với những biểu hiện thông thường. Số điện thoại phức tạp khủng khiếp để xác thực đầy đủ. –

1

Dưới đây là một số trường hợp sử dụng, được phép của Steve Yegge: Rich Programmer Food.

+0

+1 cho bài đăng trên blog cá nhân. Tôi đã mua ba cuốn sách về trình biên dịch, sự tái diễn và những thứ liên quan sau khi đọc =) –

+0

Cảm ơn. Trong trường hợp đó, hãy xem: http://stackoverflow.com/questions/725372/which-programming-languages-text –

3

bạn cần một phân tích cú pháp khi:

  1. ngôn ngữ không phải là thường xuyên (wikipedia)
  2. bạn cần một cây phân tích cú pháp (tổng quát hơn khi bạn cần phải thực hiện hành động theo ngữ cảnh)
  3. khi biểu hiện thường xuyên kết quả quá tối nghĩa/phức tạp

2 xu của tôi.

+0

Tôi không có nghĩa là để nitpick, nhưng đối với điểm 1, chúng ta cần một lexer hoặc một phân tích cú pháp? – Parag

2

The Dragon Book có một phần nhỏ về những gì bạn không thể sử dụng Regular Expressions cho:

  • Họ không thể phát hiện sự lặp lại của một chuỗi, nghĩa là bạn không thể phù hợp với cấu trúc như 'WCW, nơi w Bạn có thể chỉ phát hiện số lần lặp lại cố định hoặc số lần lặp lại không xác định, tức là bạn không thể sử dụng mã thông báo đã được phân tích cú pháp để xác định số lần lặp lại, chẳng hạn như: 'n s1 s2 ... sn '
  • "Cụm từ thông dụng không thể được sử dụng để mô tả các cấu trúc cân bằng hoặc lồng nhau, [ như] bộ dây của tất cả các dấu ngoặc đơn cân bằng"

Đối với 1 và 2, có một lời giải thích đơn giản, bạn có thể không chụp một chuỗi con, do đó bạn có thể kết hợp nó sau này. Nếu bạn muốn, hơn bạn sẽ sử dụng một trình phân tích cú pháp. Chỉ cần suy nghĩ về cách bạn sẽ sử dụng biểu thức chính quy cho những trường hợp đó, và bạn sẽ trực giác đi đến kết luận bạn không thể. :)

Đối với 3, nó giống với vấn đề trong K & R để phân tích cú pháp chuỗi ký tự. Bạn không thể chỉ nói chuỗi chữ là giữa chữ cái đầu tiên "" và chữ cái thứ hai "", nhưng điều gì sẽ xảy ra khi có dấu trích dẫn (\ ")?

Về mối quan hệ với nghịch lý của Russel, tôi nghĩ Bạn đang linh cảm là đúng, bởi vì vấn đề là khả năng introspection giới hạn của regex.Đó là tài liệu tham khảo cho các bằng chứng.Nếu bạn muốn, tôi có thể tìm chúng cho bạn

+0

Các cơ sở cho mỗi đối số là gì? 1. không suy luận về chính nó 2. vì bộ nhớ bị hạn chế, mã thông báo phải là hữu hạn 3. tất cả - Tôi không biết tại sao nhưng khi đọc bài viết, tôi bắt đầu nghĩ về nghịch lý của Russell. Bạn có thể giảm bằng chứng của họ cho nó? –

+0

Tôi đã cập nhật câu trả lời của mình. –

+0

@Asdrei Vajna II Hãy thử "% s @ \\ (h \\ (el \\) lo \\) @ chuỗi là \ 1 và chuỗi con là \ 2 @", khi bạn chỉ có một dòng với một từ "hello". –

0

Có những điều mà regex không thể làm trong khi phân tích cú pháp có thể làm
Ví dụ:.

Bắt đầu :: = (Nội);
Nội :: = Start | x;

Cụm từ thông dụng sẽ không thể thực hiện điều đó vì regex không thể theo dõi nếu có cùng số dấu ngoặc đơn mở và đóng. Đó là lý do tại sao khi bạn cố gắng mã hóa và phân tích cú pháp một tệp lớn, trình phân tích cú pháp được dự kiến ​​sẽ được sử dụng, trong khi regex chỉ có thể tìm thấy (các) mẫu đặc biệt bên trong tệp.

Các vấn đề liên quan