Bây giờ bạn có hai vấn đề gì?


200

một câu nói phổ biến của Jamie Zawinski :

Một số người, khi đối mặt với một vấn đề, nghĩ rằng "Tôi biết, tôi sẽ sử dụng các biểu thức thông thường." Bây giờ họ có hai vấn đề.

Làm thế nào là trích dẫn này được hiểu là?


46
Vấn đề thứ hai là họ đang sử dụng regex và vẫn chưa giải quyết được vấn đề đầu tiên, do đó có 2 vấn đề.
Ampt

24
@Euphoric - thực ra, mã tốt ngắn - nhưng không được mã hóa ngắn gọn.
Steve314

24
@IQAndreas: Tôi nghĩ nó có ý định bán hài hước. Nhận xét đang được đưa ra là nếu bạn không cẩn thận, sử dụng các biểu thức thông thường có thể làm mọi thứ tồi tệ hơn thay vì tốt hơn.
Thất vọngWithFormsDesigner

145
Một số người, khi cố gắng giải thích điều gì đó, nghĩ rằng "Tôi biết, tôi sẽ sử dụng một trích dẫn của Jamie Zawinski." Bây giờ họ có hai điều để giải thích.
gièm pha

Câu trả lời:


220

Một số công nghệ lập trình thường không được các lập trình viên hiểu rõ ( biểu thức chính quy , dấu phẩy động , Perl , AWK , IoC ... và các công nghệ khác ).

Đây có thể là những công cụ mạnh mẽ đáng kinh ngạc để giải quyết đúng vấn đề. Các biểu thức chính quy đặc biệt rất hữu ích để kết hợp các ngôn ngữ thông thường. Và có một mấu chốt của vấn đề: ít người biết cách mô tả một ngôn ngữ thông thường (đó là một phần của lý thuyết / ngôn ngữ học khoa học máy tính sử dụng các ký hiệu ngộ nghĩnh - bạn có thể đọc về nó theo phân cấp Chomsky ).

Khi xử lý những điều này, nếu bạn sử dụng sai, không chắc bạn đã thực sự giải quyết được vấn đề ban đầu của mình. Sử dụng biểu thức chính quy để khớp với HTML (một sự xuất hiện quá phổ biến) sẽ có nghĩa là bạn sẽ bỏ lỡ các trường hợp cạnh. Và bây giờ, bạn vẫn gặp phải vấn đề ban đầu mà bạn chưa giải quyết và một lỗi tinh vi khác xuất hiện xung quanh đã được đưa ra bằng cách sử dụng giải pháp sai.

Điều này không có nghĩa là không nên sử dụng các biểu thức thông thường, mà là người ta nên làm việc để hiểu tập hợp vấn đề họ có thể giải quyết và không thể giải quyết và sử dụng chúng một cách thận trọng.

Chìa khóa để duy trì phần mềm là viết mã duy trì. Sử dụng các biểu thức thông thường có thể phản lại mục tiêu đó. Khi làm việc với các biểu thức thông thường, bạn đã viết một máy tính mini (cụ thể là máy tự động trạng thái hữu hạn không xác định ) bằng ngôn ngữ cụ thể của miền. Thật dễ dàng để viết tương đương 'Xin chào thế giới' bằng ngôn ngữ này và có được sự tin tưởng thô sơ về ngôn ngữ này, nhưng cần phải tiếp tục tìm hiểu ngôn ngữ thông thường để tránh viết thêm các lỗi có thể rất khó xác định và sửa chữa (bởi vì chúng không phải là một phần của chương trình mà biểu thức chính quy nằm trong).

Vì vậy, bây giờ bạn đã có một vấn đề mới; bạn đã chọn công cụ của biểu thức chính quy để giải quyết nó (khi nó không phù hợp) và bây giờ bạn có hai lỗi, cả hai đều khó tìm hơn, vì chúng bị ẩn trong một lớp trừu tượng khác.


8
Tôi không chắc chắn bản thân perl thuộc danh sách các công nghệ không được các lập trình viên hiểu rõ;)
crad

21
@crad hơn nữa người ta đã nói về perl quá ... Nhiều người đã nghe nó phổ biến ở đó. Tôi vẫn thích điểm nổi trong cuộc nói chuyện rand: "Bây giờ bạn có 2.00000152 vấn đề"

56
@crad Một số người, khi gặp vấn đề, nghĩ rằng "Tôi biết, tôi sẽ sử dụng perl." Bây giờ họ có vấn đề $ (^ @ #% () ^%) (#).
Michael Hampton

4
@ Nếu có bất cứ điều gì, sức mạnh bổ sung của PCRE so với regex truyền thống làm cho nó trở thành một giải pháp hấp dẫn hơn khó duy trì hơn. Máy tự động hữu hạn mà PCRE phù hợp được khám phá trong Mở rộng tự động hữu hạn để kết hợp hiệu quả các biểu thức chính quy tương thích Perl ... và đó là một điều không tầm thường. Ít nhất là với regex truyền thống, người ta có thể quay đầu xung quanh nó mà không gặp quá nhiều rắc rối một khi các khái niệm cần thiết được hiểu.

6
Bạn làm cho một điểm tốt. biểu thức chính quy là một ngôn ngữ thứ hai, không tầm thường. Ngay cả khi lập trình viên gốc có khả năng sử dụng ngôn ngữ chính và hương vị của regex được sử dụng, việc thêm vào "ngôn ngữ thứ hai" có nghĩa là tỷ lệ cược thấp hơn mà người bảo trì sẽ biết cả hai. Chưa kể rằng khả năng đọc regex thường thấp hơn ngôn ngữ "máy chủ".
JS.

95

Các biểu thức chính quy - đặc biệt là các biểu thức không tầm thường - có khả năng khó viết mã, hiểu và duy trì. Bạn chỉ cần nhìn vào số lượng câu hỏi trên Stack Overflow được gắn thẻ [regex]nơi người hỏi đã cho rằng câu trả lời cho vấn đề của họ là một biểu thức chính quy và sau đó đã bị mắc kẹt. Trong rất nhiều trường hợp, vấn đề có thể (và có lẽ nên) được giải quyết theo một cách khác.

Điều này có nghĩa là, nếu bạn quyết định sử dụng regex, bây giờ bạn có hai vấn đề:

  1. Vấn đề ban đầu bạn muốn giải quyết.
  2. Sự hỗ trợ của một regex.

Về cơ bản, tôi nghĩ rằng anh ta có nghĩa là bạn chỉ nên sử dụng một biểu thức chính quy nếu không có cách nào khác để giải quyết vấn đề của bạn. Một giải pháp khác có lẽ sẽ dễ dàng hơn để viết mã, bảo trì và hỗ trợ. Nó có thể chậm hơn hoặc kém hiệu quả hơn, nhưng nếu điều đó không dễ bảo trì và hỗ trợ thì đó sẽ là mối quan tâm lớn nhất.


27
Và tệ hơn nữa: chúng chỉ đủ mạnh để lừa mọi người cố gắng sử dụng chúng để phân tích những thứ họ không thể, như HTML. Xem nhiều câu hỏi về SO về "làm cách nào để phân tích HTML?"
Frank Shearar

6
Đối với một số tình huống regex là tuyệt vời. Trong nhiều trường hợp khác không quá nhiều. Ở đầu kia là một hố sâu tuyệt vọng. Vấn đề thường phát sinh khi ai đó tìm hiểu về chúng lần đầu tiên và bắt đầu thấy các ứng dụng ở mọi nơi. Một câu nói nổi tiếng khác: "Khi công cụ duy nhất bạn có là một cái búa, mọi thứ trông giống như một cái đinh".
Todd Williamson

3
Điều này có nghĩa là theo số lượng câu hỏi trong thẻ SO [c #], đây là ngôn ngữ lập trình khó hiểu nhất?

2
Tôi thà thấy một biểu thức chính quy phức tạp hơn là một chuỗi dài các lệnh gọi đến các phương thức chuỗi. OTOH, tôi thực sự ghét nhìn thấy các biểu thức thông thường bị lạm dụng để phân tích các ngôn ngữ phức tạp.
kevin cline

5
"Về cơ bản, tôi nghĩ rằng anh ta có nghĩa là bạn chỉ nên sử dụng một biểu thức chính quy nếu không có cách nào khác để giải quyết vấn đề của bạn. Mọi giải pháp khác sẽ dễ dàng hơn để viết mã, duy trì và hỗ trợ." - không đồng ý nghiêm túc .. Regexes là công cụ tuyệt vời, bạn chỉ cần biết giới hạn của chúng. Rất nhiều nhiệm vụ có thể được mã hóa thanh lịch hơn với regexes. (nhưng, chỉ để làm ví dụ, bạn không nên sử dụng chúng để phân tích HTML)
Karoly Horvath

69

Nó chủ yếu là một trò đùa lưỡi, mặc dù với một sự thật.

Có một số nhiệm vụ mà biểu thức chính quy là một sự phù hợp tuyệt vời. Tôi đã từng thay thế 500 dòng mã trình phân tích cú pháp gốc đệ quy được viết thủ công bằng một biểu thức chính quy mất khoảng 10 phút để gỡ lỗi hoàn toàn. Mọi người nói regex rất khó hiểu và gỡ lỗi, nhưng những cái được áp dụng một cách thích hợp không khó để gỡ lỗi như một trình phân tích cú pháp được thiết kế bằng tay khổng lồ. Trong ví dụ của tôi, phải mất hai tuần để gỡ lỗi tất cả các trường hợp biên của giải pháp phi regex.

Tuy nhiên, để diễn giải chú Ben:

Với biểu cảm tuyệt vời đi kèm với trách nhiệm lớn.

Nói cách khác, regexes thêm biểu cảm cho ngôn ngữ của bạn, nhưng điều đó đặt ra nhiều trách nhiệm hơn cho người lập trình để chọn chế độ biểu đạt dễ đọc nhất cho một tác vụ nhất định.

Một số thứ ban đầu trông giống như một nhiệm vụ tốt cho các biểu thức thông thường, nhưng không. Ví dụ: mọi thứ có mã thông báo lồng nhau, như HTML. Đôi khi mọi người sử dụng một biểu thức chính quy khi một phương pháp đơn giản hơn rõ ràng hơn. Ví dụ, string.endsWith("ing")dễ hiểu hơn regex tương đương. Đôi khi mọi người cố gắng nhồi nhét một vấn đề lớn vào một regex duy nhất, trong đó phá vỡ nó thành từng mảnh là phù hợp hơn. Đôi khi mọi người thất bại trong việc tạo ra sự trừu tượng thích hợp, lặp đi lặp lại một biểu thức chính quy thay vì tạo ra một hàm có tên tốt để thực hiện cùng một công việc (có thể được thực hiện trong nội bộ với biểu thức chính quy).

Vì một số lý do, regexes có xu hướng kỳ lạ là tạo ra điểm mù đối với các nguyên tắc công nghệ phần mềm thông thường như trách nhiệm đơn lẻ và DRY. Đó là lý do tại sao ngay cả những người yêu thích họ đôi khi thấy họ có vấn đề.


10
Không phải chú Ben cũng nói "Kết quả hoàn hảo, mọi lúc" sao? Có lẽ đó là lý do tại sao mọi người trở nên kích hoạt hạnh phúc với regexes ...
Andrzej Doyle

4
Vấn đề với regex liên quan đến HTML khiến các nhà phát triển thiếu kinh nghiệm gặp phải là HTML có ngữ pháp không ngữ cảnh, không thường xuyên: regex có thể được sử dụng cho một số phân tích cú pháp HTML (hoặc XML) đơn giản (ví dụ: lấy URL từ thẻ neo có tên), nhưng không phù hợp cho bất cứ điều gì phức tạp. Cho rằng, phân tích cú pháp DOM là phù hợp hơn. Đọc liên quan: hệ thống phân cấp Chomsky .

53

Jeff Atwood đưa ra một cách giải thích khác nhau trong một bài đăng trên blog thảo luận về chính trích dẫn này: Biểu thức thông thường: Bây giờ bạn có hai vấn đề (nhờ Euphoric cho liên kết)

Phân tích toàn bộ bài viết của Jamie trong chủ đề gốc năm 1997, chúng tôi thấy như sau:

Bản chất của Perl khuyến khích việc sử dụng các biểu thức chính quy gần như loại trừ tất cả các kỹ thuật khác; họ ở xa và cách xa "rõ ràng" nhất (ít nhất là đối với những người không biết gì hơn) để đi từ điểm A đến điểm B.

Các trích dẫn đầu tiên là quá glib để được thực hiện nghiêm túc. Nhưng điều này, tôi hoàn toàn đồng ý với. Đây là điểm mà Jamie đang cố gắng thực hiện: không phải những biểu hiện thông thường là xấu xa, mà là lạm dụng những biểu hiện thông thường là xấu xa.

Thậm chí nếu bạn làm hoàn toàn hiểu được biểu thức thông thường, bạn chạy vào The Golden Hammer vấn đề, cố gắng giải quyết một vấn đề với biểu thức thông thường, khi nó sẽ được dễ dàng hơn và rõ ràng hơn để làm điều tương tự với mã thường xuyên (xem thêm CodingHorror: Sử dụng Regex so với lạm dụng Regex ).

Có một bài viết trên blog khác nhìn vào bối cảnh của trích dẫn và đi sâu vào chi tiết hơn Atwood: Blog của Jeffrey Friedl: Nguồn của cuốn sách nổi tiếng Bây giờ bạn có hai vấn đề trích dẫn


3
Đây là, theo tôi, câu trả lời tốt nhất bởi vì nó thêm bối cảnh. sự chỉ trích của jwz về regexes cũng nhiều như Perl.
Evicatos

3
@Evicatos Thậm chí còn có nhiều nghiên cứu được thực hiện trên cùng một chủ đề năm 1997 trong một bài đăng trên blog khác: regex.info/blog/2006-09-15/247
IQAndreas

30

Có một vài điều đang xảy ra với trích dẫn này.

  1. Câu trích dẫn là một sự phục hồi của một trò đùa trước đó:

    Bất cứ khi nào phải đối mặt với một vấn đề, một số người nói "Hãy sử dụng AWK." Bây giờ họ có hai vấn đề. - D. Tilbrook

    Đó là một trò đùa và một đào thực sự, nhưng đó cũng là một cách làm nổi bật regex như một giải pháp tồi bằng cách liên kết nó với các giải pháp xấu khác. Đó là một khoảnh khắc tuyệt vời ha ha chỉ nghiêm trọng .

  2. Đối với tôi, tâm trí của bạn, trích dẫn này được mở ra một cách có chủ đích để giải thích, ý nghĩa của nó là thẳng tiến. Đơn giản chỉ cần thông báo ý tưởng sử dụng một biểu thức thông thường đã không giải quyết được vấn đề. Ngoài ra, bạn đã tăng độ phức tạp về nhận thức của mã bằng cách thêm một ngôn ngữ bổ sung với các quy tắc khác biệt với bất kỳ ngôn ngữ nào bạn đang sử dụng.

  3. Mặc dù buồn cười như một trò đùa, bạn cần so sánh độ phức tạp của một giải pháp phi regex với độ phức tạp của giải pháp regex + độ phức tạp bổ sung bao gồm các biểu thức chính quy. Có thể đáng để giải quyết vấn đề với regex, mặc dù chi phí bổ sung thêm regexes.


21

Chính quy Expressions

. không biết rằng bạn có thể làm được.)


Đây là một ví dụ tầm thường:

^(?:[^,]*+,){21}[^,]*+$


Dù sao nó không thực sự khó đọc hay duy trì, nhưng thậm chí còn dễ hơn khi nó trông như thế này:

(?x)    # enables comments, so this whole block can be used in a regex.
^       # start of string

(?:     # start non-capturing group
  [^,]*+  # as many non-commas as possible, but none required
  ,       # a comma
)       # end non-capturing group
{21}    # 21 of previous entity (i.e. the group)

[^,]*+  # as many non-commas as possible, but none required

$       # end of string

Đó là một ví dụ điển hình (bình luận $gần giống với nhận xét i++) nhưng rõ ràng không có vấn đề gì trong việc đọc, hiểu và duy trì điều đó.


Miễn là bạn rõ ràng khi nào các biểu thức thông thường phù hợp và khi chúng là một ý tưởng tồi, không có gì sai với chúng và hầu hết các lần trích dẫn JWZ không thực sự được áp dụng.


1
Chắc chắn, nhưng tôi không tìm kiếm các cuộc thảo luận về giá trị của regex và tôi không muốn thấy cuộc thảo luận này diễn ra theo cách đó. Tôi chỉ đang cố gắng để hiểu những gì anh ấy đang nhận được.
Paul Biggar

1
Sau đó, liên kết trong nhận xét của livibetter cho bạn biết những gì bạn cần biết. Phản hồi này chỉ chỉ ra rằng regexes không cần phải tối nghĩa, và do đó trích dẫn là vô nghĩa.
Peter Boughton

8
Điểm của việc sử dụng là *+gì? Làm thế nào là bất kỳ khác nhau (chức năng) từ chỉ *?
Timwi

1
Mặc dù những gì bạn nói có thể đúng, nhưng nó không trả lời câu hỏi cụ thể này. Câu trả lời của bạn sôi nổi đến "theo ý kiến ​​của tôi rằng trích dẫn thường không đúng". Câu hỏi không phải là liệu nó có đúng hay không, mà là câu trích dẫn nghĩa là gì.
Bryan Oakley

2
Thực sự không có điểm nào trong *+trường hợp này; tất cả mọi thứ đều được neo và có thể được khớp trong một lần chạy bằng một máy tự động có thể đếm tới 22. Công cụ sửa đổi chính xác trên các bộ không dấu phẩy này chỉ đơn giản là cũ *. (Hơn nữa, cũng không nên có sự khác biệt giữa các thuật toán kết hợp tham lam và không tham lam ở đây. Đây là một trường hợp cực kỳ đơn giản.)
Donal Fellows

14

Ngoài câu trả lời của ChrisF - rằng các biểu thức thông thường "khó mã hóa, hiểu và duy trì", còn tệ hơn: chúng chỉ đủ mạnh để lừa mọi người cố gắng sử dụng chúng để phân tích những thứ họ không thể, như HTML. Xem nhiều câu hỏi về SO về "làm cách nào để phân tích HTML?" Chẳng hạn, câu trả lời hoành tráng nhất trong tất cả các SO!


14

Biểu thức thông thường rất mạnh mẽ, nhưng chúng có một vấn đề nhỏ và lớn; chúng khó viết và gần như không thể đọc được.

Trong trường hợp tốt nhất, việc sử dụng biểu thức chính quy sẽ giải quyết vấn đề, do đó bạn chỉ gặp vấn đề bảo trì mã phức tạp. Nếu bạn không có biểu thức chính quy vừa phải, bạn có cả vấn đề ban đầu và vấn đề với mã không thể đọc được mà không hoạt động.

Đôi khi các biểu thức chính quy được gọi là mã chỉ ghi. Đối mặt với một biểu thức thông thường cần sửa chữa, thường bắt đầu từ đầu nhanh hơn là cố gắng hiểu biểu thức.


1
Vấn đề thực sự là regexps không thể thực hiện, ví dụ như trình phân tích cú pháp vì chúng không thể đếm được mức độ lồng nhau hiện tại của chúng.

4
@ Thorbjørn Ravn Andersen: Đó là một hạn chế hơn là một vấn đề. Đó chỉ là vấn đề nếu bạn cố gắng sử dụng các biểu thức chính quy cho điều đó, và sau đó nó không phải là vấn đề với các biểu thức thông thường, đó là vấn đề với lựa chọn phương pháp của bạn.
Guffa

1
Bạn có thể sử dụng REs tốt cho lexer (tốt, đối với hầu hết các ngôn ngữ) nhưng lắp ráp luồng mã thông báo thành cây phân tích cú pháp (nghĩa là phân tích cú pháp ) chính thức vượt ra ngoài chúng.
Donal Fellows

10

Vấn đề là regex là một con thú phức tạp và bạn chỉ giải quyết vấn đề của mình nếu bạn sử dụng regex một cách hoàn hảo. Nếu bạn không, bạn kết thúc với 2 vấn đề: vấn đề ban đầu regex của bạn.

Bạn tuyên bố rằng nó có thể thực hiện công việc của một trăm dòng mã, nhưng bạn cũng có thể đưa ra lập luận rằng 100 dòng mã rõ ràng, súc tích sẽ tốt hơn một dòng regex.

Nếu bạn cần một số bằng chứng về điều này: Bạn có thể kiểm tra SO Classic này hoặc đơn giản là kết hợp thông qua Thẻ SO Regex


8
Cả hai yêu cầu trong câu đầu tiên của bạn đều đúng. Regex không đặc biệt phức tạp, và giống như không có công cụ nào khác, bạn cần phải biết nó một cách hoàn hảo để giải quyết vấn đề với nó. Đó chỉ là FUD. Đoạn thứ hai của bạn thật vô lý: tất nhiên bạn có thể đưa ra lập luận. Nhưng nó không phải là một thứ tốt.
Konrad Rudolph

1
@KonradRudolph Tôi nghĩ rằng thực tế là có rất nhiều công cụ xác thực và tạo regex sẽ cho thấy rằng regex một cơ chế phức tạp. Nó không phải là con người có thể đọc được (theo thiết kế) và có thể gây ra sự thay đổi hoàn toàn trong luồng cho ai đó sửa đổi hoặc viết một đoạn mã sử dụng regex. Về phần thứ hai, tôi nghĩ rằng nó rõ ràng trong hàm ý của nhóm kiến ​​thức rộng lớn trên P.SE và bằng câu nói "Mã gỡ lỗi khó gấp đôi so với viết nó, vì vậy nếu bạn viết mã thông minh nhất bạn có thể, bạn theo định nghĩa, không đủ thông minh để gỡ lỗi "
Ampt

2
Đó không phải là một lập luận đúng đắn. Vâng, chắc chắn regex rất phức tạp. Nhưng các ngôn ngữ lập trình khác cũng vậy. Regex ít phức tạp hơn đáng kể so với hầu hết các ngôn ngữ khác và các công cụ tồn tại cho regex bị lấn át bởi các công cụ phát triển cho các ngôn ngữ khác (FWIW Tôi làm việc nhiều với regex và tôi chưa bao giờ sử dụng các công cụ như vậy). Đó là một sự thật đơn giản rằng ngay cả regex phức tạp cũng đơn giản hơn mã phân tích cú pháp không regex tương đương.
Konrad Rudolph

@KonradRudolph Tôi nghĩ rằng chúng ta có một sự bất đồng cơ bản về định nghĩa của từ đơn giản sau đó. Tôi sẽ cung cấp cho bạn rằng regex có thể hiệu quả hơn hoặc thậm chí mạnh hơn nhưng tôi không nghĩ rằng đơn giản là từ xuất hiện trong tâm trí của bất kỳ ai khi bạn nghĩ về regex.
Ampt

Có thể chúng tôi làm nhưng định nghĩa của tôi là có thể thực hiện được: Tôi đơn giản có nghĩa là dễ hiểu, dễ bảo trì, số lượng lỗi thấp, v.v ... Tất nhiên, một biểu thức phức tạp thoạt nhìn sẽ không dễ hiểu lắm. Nhưng điều tương tự cũng đúng với một đoạn mã không phải regex tương đương. Tôi chưa bao giờ nói rằng regex rất đơn giản. Tôi đang nói họ đơn giản hơn - tôi đang so sánh. Đó là quan trọng.
Konrad Rudolph

7

Ý nghĩa có hai phần:

  • Đầu tiên, bạn không giải quyết được vấn đề ban đầu.
    Điều này có lẽ đề cập đến thực tế là các biểu thức thông thường thường cung cấp các giải pháp không đầy đủ cho các vấn đề phổ biến.
  • Thứ hai, bây giờ bạn đã thêm khó khăn bổ sung liên quan đến giải pháp bạn đã chọn.
    Trong trường hợp biểu thức chính quy, khó khăn bổ sung có thể liên quan đến độ phức tạp, khả năng duy trì hoặc khó khăn bổ sung liên quan đến việc tạo biểu thức chính quy phù hợp với một vấn đề mà nó không cần phải giải quyết.

7

Khi bạn yêu cầu nó vào năm 2014, sẽ rất thú vị khi tập trung vào hệ tư tưởng ngôn ngữ lập trình của bối cảnh năm 1997 so với bối cảnh ngày nay. Tôi sẽ không tham gia cuộc tranh luận này ở đây nhưng ý kiến ​​về Perl và bản thân Perl đã thay đổi rất nhiều.

Tuy nhiên, để ở trong bối cảnh năm 2013 ( de l'eau a coulé sous les ponts depuis), tôi khuyên bạn nên tập trung vào việc tái hiện trong các trích dẫn bằng truyện tranh XKCD nổi tiếng là một trích dẫn trực tiếp của Jamie Zawinski :

Truyện tranh từ XKCD về regexes, Perl và các vấn đề

Đầu tiên tôi gặp vấn đề để hiểu truyện tranh này vì nó liên quan đến trích dẫn của Zawinski, trích dẫn lời bài hát của Jay-z, một tài liệu tham khảo về program --help -zcờ GNU 2 , vì vậy, nó quá nhiều văn hóa để tôi hiểu nó.

Tôi biết điều đó thật thú vị, tôi đã cảm nhận được điều đó, nhưng tôi không thực sự biết tại sao. Mọi người thường đùa giỡn về Perl và regexes, đặc biệt vì đây không phải là ngôn ngữ lập trình mạnh mẽ nhất, không thực sự biết tại sao nó được cho là vui vẻ ... Có lẽ vì những người mong muốn Perl làm những điều ngớ ngẩn .

Vì vậy, trích dẫn ban đầu dường như là một trò đùa châm biếm dựa trên các vấn đề thực tế (đau?) Gây ra bởi lập trình với các công cụ gây tổn thương. Giống như một cái búa có thể làm tổn thương thợ xây, lập trình với các công cụ không phải là công cụ mà nhà phát triển sẽ chọn nếu anh ta có thể làm tổn thương (não, cảm xúc). Đôi khi, những cuộc tranh luận lớn về công cụ nào là tốt nhất xảy ra, nhưng nó gần như vô giá trị vì nó là một vấn đề của khẩu vị của bạn hoặc hương vị đội ngũ lập trình của bạn , văn hóa hoặc kinh tế lý do. Một truyện tranh XKCD xuất sắc khác về điều này:

Truyện tranh từ XKCD về các công cụ lập trình tranh luận

Tôi có thể hiểu mọi người cảm thấy đau đớn về regexes và họ tin rằng một công cụ khác phù hợp hơn với những gì regexes được thiết kế cho. Khi @ karl-bielefeldt trả lời câu hỏi của bạn với tính biểu cảm cao sẽ có trách nhiệm lớn và các biểu thức đặc biệt quan tâm đến vấn đề này. Nếu một nhà phát triển không quan tâm đến cách họ xử lý các biểu thức, cuối cùng sẽ là một nỗi đau cho những người sẽ duy trì mã sau này.

Tôi sẽ kết thúc với câu trả lời này về việc trích dẫn lại bằng một trích dẫn cho thấy một ví dụ điển hình từ Thực tiễn tốt nhất của Damian Conw ay Perl (một cuốn sách năm 2005).

Ông giải thích rằng viết một mô hình như thế này:

m{'[^\\']*(?:\\.[^\\']*)*'}

... không thể chấp nhận hơn là viết một chương trình như thế này :

sub'x{local$_=pop;sub'_{$_>=$_[0
]?$_[1]:$"}_(1,'*')._(5,'-')._(4
,'*').$/._(6,'|').($_>9?'X':$_>8
?'/':$")._(8,'|').$/._(2,'*')._(
7,'-')._(3,'*').$/}print$/x($=).
x(10)x(++$x/10).x($x%10)while<>;

Nhưng nó có thể được viết lại , nó vẫn không đẹp, nhưng ít nhất bây giờ nó có thể sống sót.

# Match a single-quoted string efficiently...
m{ '            # an opening single quote
    [^\\']*     # any non-special chars (i.e., not backslash or single quote)
    (?:         # then all of...`
    \\ .        # any explicitly backslashed char
    [^\\']*     #    followed by any non-special chars
    )*          # ...repeated zero or more times
    '           # a closing single quote
}x

Loại mã hình chữ nhật này là vấn đề thứ hai không phải là biểu thức có thể được định dạng theo cách rõ ràng, có thể duy trì và có thể đọc được.


2
/* Multiply the first 10 values in an array by 2. */ for (int i = 0 /* the loop counter */; i < 10 /* continue while it is less than 10 */; ++i /* and increment it by 1 in each iteration */) { array[i] *= 2; /* double the i-th element in the array */ }
5gon12eder

6

Nếu có một điều bạn nên học từ khoa học máy tính, đó là hệ thống phân cấp Chomsky . Tôi muốn nói rằng tất cả các vấn đề với các biểu thức thông thường đến từ các nỗ lực phân tích ngữ pháp không ngữ cảnh với nó. Khi bạn có thể áp đặt một giới hạn (hoặc nghĩ rằng bạn có thể áp đặt một giới hạn) cho các mức lồng nhau trong CFG, bạn sẽ có được các biểu thức chính quy dài và phức tạp đó.


1
Đúng! Những người học biểu thức thông thường mà không có một phần của nền CS không phải lúc nào hiểu rằng đó chỉ là một số điều mà một regex về mặt toán học không thể làm.
benzado

5

Các biểu thức thông thường phù hợp với mã thông báo hơn là phân tích toàn bộ quy mô.

Nhưng, một tập hợp lớn những điều đáng ngạc nhiên mà các lập trình viên cần phân tích cú pháp có thể được phân tích cú pháp bằng một ngôn ngữ thông thường (hoặc tệ hơn, gần như có thể phân tích cú pháp bằng một ngôn ngữ thông thường và nếu bạn chỉ viết thêm một chút mã ...).

Vì vậy, nếu một người đã quen với "aha, tôi cần phải tách văn bản ra, tôi sẽ sử dụng một biểu thức chính quy", thật dễ dàng để đi theo tuyến đường đó, khi bạn cần một cái gì đó gần hơn với máy tự động đẩy xuống, trình phân tích cú pháp CFG hoặc thậm chí ngữ pháp mạnh mẽ hơn. Điều đó thường kết thúc trong nước mắt.

Vì vậy, tôi nghĩ rằng trích dẫn không phải là quá nhiều các biểu thức chính tả, chúng có công dụng của chúng (và được sử dụng tốt, chúng thực sự rất hữu ích), nhưng sự phụ thuộc quá mức vào các biểu thức chính quy (hay cụ thể là sự lựa chọn không chính xác của chúng) .


3

jwz chỉ đơn giản là tắt rocker của mình với trích dẫn đó. các biểu thức thông thường không khác gì bất kỳ tính năng ngôn ngữ nào - dễ dàng sử dụng, khó sử dụng một cách thanh lịch, mạnh mẽ, đôi khi không phù hợp, thường được ghi chép tốt, thường hữu ích.

điều tương tự cũng có thể được nói đối với số học dấu phẩy động, bao đóng, hướng đối tượng, I / O không đồng bộ hoặc bất cứ thứ gì khác mà bạn có thể đặt tên. nếu bạn không biết bạn đang làm gì, ngôn ngữ lập trình có thể khiến bạn buồn.

nếu bạn nghĩ regexes khó đọc, hãy thử đọc triển khai trình phân tích cú pháp tương đương để sử dụng mẫu đang đề cập. thường regexes giành chiến thắng vì chúng nhỏ gọn hơn các trình phân tích cú pháp đầy đủ ... và trong hầu hết các ngôn ngữ, chúng cũng nhanh hơn.

không được sử dụng các biểu thức thông thường (hoặc bất kỳ tính năng ngôn ngữ nào khác) vì một blogger tự quảng cáo đưa ra các tuyên bố không đủ tiêu chuẩn. thử mọi thứ cho chính mình và xem những gì làm việc cho bạn.


1
FWIW, số học dấu phẩy động là waaay khó hơn REs, nhưng có vẻ đơn giản hơn. Coi chừng! (Ít nhất các RE khó khăn có xu hướng trông nguy hiểm.)
Donal Fellows

3

Câu trả lời chuyên sâu, yêu thích của tôi về câu hỏi này được đưa ra bởi Rob Pike nổi tiếng trong một bài đăng trên blog được sao chép từ một nhận xét mã nội bộ của Google: http://commandcenter.blogspot.ch/2011/08/THER-expressions-in-lexing- và.html

Tóm tắt là không phải là chúng xấu , nhưng chúng thường được sử dụng cho các nhiệm vụ vì chúng không nhất thiết phải phù hợp, đặc biệt là khi nói đến việc lexing và phân tích một số đầu vào.

Các biểu thức thông thường khó viết, khó viết tốt và có thể tốn kém so với các công nghệ khác ... Mặt khác, bộ xử lý khá dễ viết chính xác (nếu không gọn nhẹ) và rất dễ kiểm tra. Xem xét việc tìm định danh chữ và số. Không quá khó để viết regrec (một cái gì đó như "[a-ZA-Z _] [a-ZA-Z_0-9] *"), nhưng thực sự không khó để viết như một vòng lặp đơn giản. Hiệu suất của vòng lặp, tuy nhiên, sẽ cao hơn nhiều và sẽ liên quan đến mã ít hơn nhiều dưới vỏ bọc. Một thư viện biểu thức chính quy là một điều lớn. Sử dụng một để phân tích số nhận dạng cũng giống như sử dụng một chiếc Ferrari để đến cửa hàng để lấy sữa.

Ông nói nhiều hơn thế, lập luận rằng các biểu thức chính quy rất hữu ích, ví dụ như kết hợp các mẫu trong các trình soạn thảo văn bản nhưng hiếm khi được sử dụng trong mã biên dịch, v.v. Nó đáng để đọc.


0

Điều này có liên quan đến epigram # 34 của Alan Perlis:

Chuỗi là một cấu trúc dữ liệu rõ ràng và ở mọi nơi nó được thông qua có nhiều sự trùng lặp của quá trình. Nó là một phương tiện hoàn hảo để che giấu thông tin.

Vì vậy, nếu bạn chọn chuỗi ký tự làm cấu trúc dữ liệu của mình (và, một cách tự nhiên, mã dựa trên regex làm thuật toán để thao tác nó), bạn có một vấn đề, ngay cả khi nó hoạt động: thiết kế xấu xung quanh việc thể hiện dữ liệu không phù hợp, khó có thể mở rộng, và không hiệu quả.

Tuy nhiên, thường thì nó không hoạt động: vấn đề ban đầu không được giải quyết, và vì vậy trong trường hợp đó bạn có hai vấn đề.


0

Regexes được sử dụng rộng rãi để phân tích văn bản nhanh và bẩn. Chúng là một công cụ tuyệt vời để thể hiện các mẫu phức tạp hơn một chút so với chỉ một chuỗi khớp đơn giản.

Tuy nhiên, khi regexes nhận được các vấn đề máy chủ phức tạp hơn, hãy ngẩng cao đầu.

  1. Cú pháp của regexes được tối ưu hóa để khớp đơn giản, hầu hết các ký tự khớp với nhau. Điều đó thật tuyệt vời cho các mẫu đơn giản nhưng một khi bạn kết thúc với hơn một vài cấp độ lồng nhau, bạn sẽ kết thúc với một cái gì đó trông giống như nhiễu dòng hơn là mã có cấu trúc tốt. Tôi đoán bạn có thể viết một biểu thức chính quy như một chuỗi các chuỗi kết hợp với thụt lề và các bình luận ở giữa để hiển thị cấu trúc của mã nhưng dường như rất hiếm khi điều đó thực sự xảy ra.
  2. Chỉ một số loại văn bản phù hợp nhất định là phù hợp với regexes. Thường thì bạn thấy mình nhận được một trình phân tích cú pháp dựa trên regex nhanh và bẩn cho một số loại ngôn ngữ đánh dấu hoạt động nhưng sau đó bạn cố gắng bao quát nhiều trường hợp góc hơn và bạn thấy các regex ngày càng phức tạp hơn và ít đọc hơn
  3. Sự phức tạp thời gian của một regex có thể không phải là obvoius. Không khó để kết thúc với một mẫu hoạt động tuyệt vời khi nó khớp nhưng có độ phức tạp O (2 ^ n) trong một số trường hợp không khớp .

Do đó, thật dễ dàng để bắt đầu với một vấn đề xử lý văn bản, áp dụng các biểu thức chính quy cho nó và kết thúc với hai vấn đề, vấn đề ban đầu mà bạn đang cố gắng giải quyết và xử lý các biểu thức thông thường đang cố gắng giải quyết (nhưng không giải quyết chính xác) vấn đề ban đầu.

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.