Tại sao các biểu thức chính quy gây tranh cãi như vậy? [đóng cửa]


212

Khi khám phá các biểu thức chính quy (còn được gọi là RegEx-es), có nhiều cá nhân dường như xem các biểu thức chính quy là Chén Thánh. Một cái gì đó trông rất phức tạp - chỉ cần là câu trả lời cho bất kỳ câu hỏi. Họ có xu hướng nghĩ rằng mọi vấn đề đều có thể giải quyết được bằng cách sử dụng các biểu thức thông thường.

Mặt khác, cũng có nhiều người cố gắng tránh các biểu thức thông thường bằng mọi giá. Họ cố gắng tìm cách xoay quanh các biểu thức thông thường và chấp nhận mã hóa bổ sung chỉ vì lợi ích của nó, ngay cả khi một biểu thức thông thường sẽ là một giải pháp nhỏ gọn hơn.

Tại sao các biểu thức chính quy được coi là gây tranh cãi? Có những hiểu lầm phổ biến về cách họ làm việc? Hoặc có thể là một niềm tin rộng rãi rằng các biểu thức thông thường nói chung là chậm?


9
Nếu đây là một cuộc thảo luận, thì nó không nên bị đóng cửa? Nhưng tôi thấy một câu hỏi thực sự trong đó vì vậy có lẽ thẻ thảo luận không thuộc về?
RCIX

6
Không đua đâu. Bạn mang nó lên và mọi người bắt đầu phát điên ở đây.
Ryan Florence

1
Quan sát tốt đẹp và từ ngữ trong câu hỏi!
imz - Ivan Zakharyaschev


Câu hỏi là ý kiến ​​dựa trên quy tắc cũng nên áp dụng ở đây (hoặc câu hỏi nên được chỉnh sửa để nhắm mục tiêu một câu trả lời chính xác). Điều đó nói rằng tôi cho rằng mâu thuẫn regex xuất phát từ sự không chính xác của các hướng dẫn và hướng dẫn sử dụng về nó. Hầu hết thời gian nếu không phải tất cả các thông tin thời gian là hỗn hợp và ngoài ra chúng tôi không được cung cấp tất cả các đặc điểm. Thêm vào đó ngôn ngữ bỏ lỡ sử dụng, cuối cùng bạn học được một điều gì đó để thông báo rằng nó có thể có nghĩa gì đó khác. Và cuối cùng các ký tự regex đặc biệt không bị giới hạn ở một nghĩa làm tăng thêm sự nhầm lẫn.
intika

Câu trả lời:


136

Tôi không nghĩ mọi người phản đối các biểu thức thông thường vì chúng chậm, nhưng vì chúng khó đọc và viết, cũng như khó để hiểu đúng. Mặc dù có một số tình huống trong đó các biểu thức chính quy cung cấp một giải pháp nhỏ gọn, hiệu quả cho vấn đề, đôi khi chúng lại bị cuốn vào các tình huống sử dụng một đoạn mã dễ đọc, dễ bảo trì thay thế.


2
Và vâng, regexes có thể cực kỳ chậm so với việc sử dụng các hàm đơn giản. Và không chỉ chậm, mà hiệu suất của công cụ regex có thể hoàn toàn không thể đoán trước khi phải đối mặt với các đầu vào tùy ý (do người dùng cung cấp).
Pacerier

1
Nếu bạn biết regex hoạt động như thế nào, thì đó không phải là vấn đề.
Shiplu Mokaddim

8
@pacerier, nó không phải mẫu chậm , nó là động cơ chậm . Hầu hết các công cụ biểu thức chính quy (hiện đại) không phù hợp với các mẫu phức tạp (ví dụ: nhiều |hoặc .*), vì chúng sử dụng máy xếp chồng và quay lui. Đó là lý do tại sao bạn phải điều chỉnh cẩn thận các biểu thức chính quy của mình trong Perl, Java, Python, Ruby, Công cụ biểu thức chính quy kiểu cũ ( grepví dụ) trước tiên biên dịch mẫu thành DFA. Sau đó, sự phức tạp của mô hình phần lớn không liên quan. Tôi chỉ sử dụng Java và grep cho cùng một văn bản và mẫu: 22 phút so với 2 giây. Đây là khoa học: swtch.com/~rsc/regapi/regapid1.html
hagello

122

Làm cho Regexes duy trì

Một tiến bộ lớn trong việc làm sáng tỏ các mẫu trước đây được gọi là biểu thức chính quy của /xHồi giáo là cờ biểu thức chính thức của Perl - đôi khi được viết(?x) khi được nhúng - cho phép khoảng trắng (ngắt dòng, thụt lề) và nhận xét. Điều này nghiêm túc cải thiện khả năng đọc và do đó khả năng bảo trì. Không gian màu trắng cho phép phân chia nhận thức, vì vậy bạn có thể xem nhóm nào với cái gì.

Các mẫu hiện đại bây giờ cũng hỗ trợ cả hai phản hồi tương đối được đánh số và đặt tên. Điều đó có nghĩa là bạn không còn cần phải đếm các nhóm chụp để tìm ra rằng bạn cần $4hoặc\7 . Điều này giúp khi tạo các mẫu có thể được bao gồm trong các mẫu hơn nữa.

Dưới đây là một ví dụ về một nhóm chụp tương đối được đánh số:

$ song ngữ = qr {\ b (?: (\ w +) (?: \ s + \ g {-1}) +) \ b} xi;
$ quoteed = qr {(["']) $ song ngữ \ 1} x;

Và đây là một ví dụ về cách tiếp cận ưu việt của các hình chụp được đặt tên:

$dupword = qr{ \b (?: (?<word> \w+ ) (?: \s+ \k<word> )+ ) \b }xi;
$quoted  = qr{ (?<quote> ["'] ) $dupword  \g{quote} }x;

Ngữ pháp ngữ pháp

Trên hết , những ảnh chụp có tên này có thể được đặt trong một (?(DEFINE)...)khối, do đó bạn có thể tách biệt khai báo khỏi việc thực thi các phần tử được đặt tên riêng lẻ của các mẫu của bạn. Điều này làm cho chúng hoạt động khá giống như chương trình con trong mẫu.
Một ví dụ điển hình về loại regex ngữ pháp này có thể được tìm thấy trong câu trả lời nàycâu trả lời này . Chúng trông giống như một tuyên bố ngữ pháp.

Như sau nhắc nhở bạn:

Hãy chắc chắn rằng không bao giờ để viết dòng ‐ mẫu nhiễu. Bạn không cần phải làm thế, và bạn không nên. Không có ngôn ngữ lập trình nào có thể được duy trì mà cấm khoảng trắng, nhận xét, chương trình con hoặc định danh chữ và số. Vì vậy, sử dụng tất cả những điều đó trong các mẫu của bạn.

Điều này không thể được nhấn mạnh quá mức. Tất nhiên, nếu bạn không sử dụng những thứ đó trong các mẫu của mình, bạn sẽ thường tạo ra một cơn ác mộng. Nhưng nếu bạn làm sử dụng chúng, tuy nhiên, bạn không cần.

Đây là một ví dụ khác về mẫu ngữ pháp hiện đại, mẫu này để phân tích RFC 5322: sử dụng 5.10.0;

$rfc5322 = qr{

   (?(DEFINE)

     (?<address>         (?&mailbox) | (?&group))
     (?<mailbox>         (?&name_addr) | (?&addr_spec))
     (?<name_addr>       (?&display_name)? (?&angle_addr))
     (?<angle_addr>      (?&CFWS)? < (?&addr_spec) > (?&CFWS)?)
     (?<group>           (?&display_name) : (?:(?&mailbox_list) | (?&CFWS))? ; (?&CFWS)?)
     (?<display_name>    (?&phrase))
     (?<mailbox_list>    (?&mailbox) (?: , (?&mailbox))*)

     (?<addr_spec>       (?&local_part) \@ (?&domain))
     (?<local_part>      (?&dot_atom) | (?&quoted_string))
     (?<domain>          (?&dot_atom) | (?&domain_literal))
     (?<domain_literal>  (?&CFWS)? \[ (?: (?&FWS)? (?&dcontent))* (?&FWS)?
                                   \] (?&CFWS)?)
     (?<dcontent>        (?&dtext) | (?&quoted_pair))
     (?<dtext>           (?&NO_WS_CTL) | [\x21-\x5a\x5e-\x7e])

     (?<atext>           (?&ALPHA) | (?&DIGIT) | [!#\$%&'*+-/=?^_`{|}~])
     (?<atom>            (?&CFWS)? (?&atext)+ (?&CFWS)?)
     (?<dot_atom>        (?&CFWS)? (?&dot_atom_text) (?&CFWS)?)
     (?<dot_atom_text>   (?&atext)+ (?: \. (?&atext)+)*)

     (?<text>            [\x01-\x09\x0b\x0c\x0e-\x7f])
     (?<quoted_pair>     \\ (?&text))

     (?<qtext>           (?&NO_WS_CTL) | [\x21\x23-\x5b\x5d-\x7e])
     (?<qcontent>        (?&qtext) | (?&quoted_pair))
     (?<quoted_string>   (?&CFWS)? (?&DQUOTE) (?:(?&FWS)? (?&qcontent))*
                          (?&FWS)? (?&DQUOTE) (?&CFWS)?)

     (?<word>            (?&atom) | (?&quoted_string))
     (?<phrase>          (?&word)+)

     # Folding white space
     (?<FWS>             (?: (?&WSP)* (?&CRLF))? (?&WSP)+)
     (?<ctext>           (?&NO_WS_CTL) | [\x21-\x27\x2a-\x5b\x5d-\x7e])
     (?<ccontent>        (?&ctext) | (?&quoted_pair) | (?&comment))
     (?<comment>         \( (?: (?&FWS)? (?&ccontent))* (?&FWS)? \) )
     (?<CFWS>            (?: (?&FWS)? (?&comment))*
                         (?: (?:(?&FWS)? (?&comment)) | (?&FWS)))

     # No whitespace control
     (?<NO_WS_CTL>       [\x01-\x08\x0b\x0c\x0e-\x1f\x7f])

     (?<ALPHA>           [A-Za-z])
     (?<DIGIT>           [0-9])
     (?<CRLF>            \x0d \x0a)
     (?<DQUOTE>          ")
     (?<WSP>             [\x20\x09])
   )

   (?&address)

}x;

Điều đó có đáng chú ý không - và lộng lẫy? Bạn có thể lấy một ngữ pháp kiểu BNF và dịch nó trực tiếp thành mã mà không làm mất cấu trúc cơ bản của nó!

Nếu các mẫu ngữ pháp hiện đại vẫn không đủ cho bạn, thì mô-đun xuất sắc của Damian ConwayRegexp::Grammars cung cấp một cú pháp thậm chí còn sạch hơn, với khả năng gỡ lỗi vượt trội. Đây là cùng một mã để phân tích cú pháp RFC 5322 đúc lại thành một mẫu từ mô-đun đó:

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;
use Data::Dumper "Dumper";

my $rfc5322 = do {
    use Regexp::Grammars;    # ...the magic is lexically scoped
    qr{

    # Keep the big stick handy, just in case...
    # <debug:on>

    # Match this...
    <address>

    # As defined by these...
    <token: address>         <mailbox> | <group>
    <token: mailbox>         <name_addr> | <addr_spec>
    <token: name_addr>       <display_name>? <angle_addr>
    <token: angle_addr>      <CFWS>? \< <addr_spec> \> <CFWS>?
    <token: group>           <display_name> : (?:<mailbox_list> | <CFWS>)? ; <CFWS>?
    <token: display_name>    <phrase>
    <token: mailbox_list>    <[mailbox]> ** (,)

    <token: addr_spec>       <local_part> \@ <domain>
    <token: local_part>      <dot_atom> | <quoted_string>
    <token: domain>          <dot_atom> | <domain_literal>
    <token: domain_literal>  <CFWS>? \[ (?: <FWS>? <[dcontent]>)* <FWS>?

    <token: dcontent>        <dtext> | <quoted_pair>
    <token: dtext>           <.NO_WS_CTL> | [\x21-\x5a\x5e-\x7e]

    <token: atext>           <.ALPHA> | <.DIGIT> | [!#\$%&'*+-/=?^_`{|}~]
    <token: atom>            <.CFWS>? <.atext>+ <.CFWS>?
    <token: dot_atom>        <.CFWS>? <.dot_atom_text> <.CFWS>?
    <token: dot_atom>        <.CFWS>? <.dot_atom_text> <.CFWS>?
    <token: dot_atom_text>   <.atext>+ (?: \. <.atext>+)*

    <token: text>            [\x01-\x09\x0b\x0c\x0e-\x7f]
    <token: quoted_pair>     \\ <.text>

    <token: qtext>           <.NO_WS_CTL> | [\x21\x23-\x5b\x5d-\x7e]
    <token: qcontent>        <.qtext> | <.quoted_pair>
    <token: quoted_string>   <.CFWS>? <.DQUOTE> (?:<.FWS>? <.qcontent>)*
                             <.FWS>? <.DQUOTE> <.CFWS>?

    <token: word>            <.atom> | <.quoted_string>
    <token: phrase>          <.word>+

    # Folding white space
    <token: FWS>             (?: <.WSP>* <.CRLF>)? <.WSP>+
    <token: ctext>           <.NO_WS_CTL> | [\x21-\x27\x2a-\x5b\x5d-\x7e]
    <token: ccontent>        <.ctext> | <.quoted_pair> | <.comment>
    <token: comment>         \( (?: <.FWS>? <.ccontent>)* <.FWS>? \)
    <token: CFWS>            (?: <.FWS>? <.comment>)*
                             (?: (?:<.FWS>? <.comment>) | <.FWS>)

    # No whitespace control
    <token: NO_WS_CTL>       [\x01-\x08\x0b\x0c\x0e-\x1f\x7f]

    <token: ALPHA>           [A-Za-z]
    <token: DIGIT>           [0-9]
    <token: CRLF>            \x0d \x0a
    <token: DQUOTE>          "
    <token: WSP>             [\x20\x09]

    }x;

};


while (my $input = <>) {
    if ($input =~ $rfc5322) {
        say Dumper \%/;       # ...the parse tree of any successful match
                              # appears in this punctuation variable
    }
}

Có rất nhiều thứ tốt đẹp trong các perlre manpage , nhưng những cải tiến đáng kể trong tính năng thiết kế regex cơ bản là không có nghĩa là giới hạn Perl một mình. Thật vậy , trang web pcrepotype có thể dễ đọc hơn và bao gồm cùng một lãnh thổ.

Các mẫu hiện đại hầu như không có gì giống với những thứ nguyên thủy mà bạn được dạy trong lớp automata hữu hạn của bạn.


9
ĐÚNG! ĐÚNG! Cuối cùng, ai đó cho thấy một ví dụ tuyệt vời về cách regexes có thể đọc được với công cụ sửa đổi x. Tôi không thể tin có bao nhiêu người biết rằng nó tồn tại, chứ đừng nói đến việc sử dụng nó.
Shabbycoat

1
@Shabbycoat: Không chỉ /x. Nó sử dụng các biểu thức chính tả theo ngữ pháp, với (?&name)các chương trình con biểu thức chính bên trong, điều đó thực sự làm cho nó tỏa sáng.
tchrist

+1 Bạn luôn học được điều gì đó mới. Tôi không biết rằng PCRE có một điều kiện "sai" để định nghĩa.
NikiC

5
Python tương tự có một re.VERBOSElá cờ.
Ốc cơ khí

3
Chỉ cần gunna đi trước và nói rằng tôi vẫn còn ngạc nhiên về độ dài mà mọi người sẽ đi để làm cho regex có thể sử dụng được.
Slater Victoroff

68

Regexes là một công cụ tuyệt vời, nhưng mọi người nghĩ rằng "Này, thật là một công cụ tuyệt vời, tôi sẽ sử dụng nó để làm X!" trong đó X là thứ mà một công cụ khác tốt hơn (thường là trình phân tích cú pháp). Đây là tiêu chuẩn sử dụng búa trong đó bạn cần một vấn đề về tuốc nơ vít.


4
Chỉ cần nhớ rằng hầu hết các trình phân tích cú pháp-phân tích cú pháp - vẫn sử dụng các biểu thức chính quy để phân tích nội dung của chúng :-)
Jasper Bekkers

62
Nói rằng các trình phân tích cú pháp sử dụng các biểu thức thông thường cũng giống như nói các trình phân tích cú pháp sử dụng các câu lệnh gán. Nó có nghĩa là không có gì cho đến khi bạn nhìn để xem chúng đang được sử dụng như thế nào.
Chas. Owens

24
Sử dụng RegEx khi trình phân tích cú pháp tốt hơn sẽ gây khó chịu. Sử dụng RegEx khi các hàm tìm hoặc thay thế chuỗi tiêu chuẩn của ngôn ngữ sẽ hoạt động (và trong thời gian tuyến tính thường) là không thể tha thứ.
jmucchiello

1
Đồng ý, bởi vì RegEx phải là người nắm giữ tất cả các giao dịch mà nó xử lý là rất lớn. Chỉ vì sử dụng công cụ RegEx có vẻ dễ dàng không có nghĩa đó là giải pháp tốt hơn so với trình phân tích cú pháp lặp (ngưỡng phụ thuộc của nhà phát triển). Một trong những ví dụ yêu thích của tôi split($pattern,$string)so với PHP explode($delimiter,$string)- rất may là cái trước đang bị mất giá, nhưng rất nhiều mã đã sử dụng cái trước khi chúng chỉ cần sức mạnh của cái sau. Đồng ý, RegEx cung cấp một công cụ dễ dàng để thực hiện một số việc nhưng trừ khi bạn cần toàn bộ sức mạnh của các biểu thức chính quy
Rudu

4
Máy phân tích từ điển thực sự có thể sử dụng regexes. Chúng còn được gọi là mã thông báo, nhưng chúng không phải là máy phân tích cú pháp (hoặc trình phân tích cú pháp). Để đọc một chuỗi đủ phức tạp, nên sử dụng mã thông báo để đọc chuỗi dưới dạng mã thông báo (có thể với regexes, có lẽ không, tùy thuộc vào mã thông báo). Các mã thông báo này sau đó sẽ được chuyển đến trình phân tích cú pháp, sẽ xử lý chúng bằng các quy tắc ngữ pháp, chắc chắn không phải là biểu thức chính quy.
Axel

53

Hầu như tất cả mọi người tôi biết, những người sử dụng các biểu thức chính quy thường xuyên (ý định chơi chữ) đến từ nền tảng Unix-ish nơi họ sử dụng các công cụ coi RE là cấu trúc lập trình hạng nhất, như grep, sed, awk và Perl. Vì hầu như không có chi phí cú pháp để sử dụng biểu thức chính quy, năng suất của chúng tăng lên khi chúng thực hiện.

Ngược lại, các lập trình viên sử dụng các ngôn ngữ trong đó RE là một thư viện bên ngoài có xu hướng không xem xét những biểu thức thông thường có thể mang lại cho bảng. Lập trình viên "chi phí thời gian" cao đến mức a) REs không bao giờ xuất hiện như một phần trong quá trình đào tạo của họ, hoặc b) họ không "nghĩ" về REs và thích quay lại với các mẫu quen thuộc hơn.


11
Vâng, tôi không bao giờ tha thứ cho Python khi thực hiện cú pháp regex dài dòng bằng cách sử dụng một thư viện. Tôi nghĩ rằng đó là sự tinh khiết trên sự tỉnh táo.
slikts

7
Tôi đến từ một nền tảng unix, đã sử dụng tải sed, awk & perl, và tất nhiên là có rất nhiều grepping, nhưng biết rằng khi tôi sử dụng regex, đó là một bản hack chỉ viết mà tôi ghét duy trì. Nó tốt cho các kịch bản shell / bộ định thời gian, nhưng đối với công việc thực tế, đối với mọi thứ không chỉ là lấy một số dữ liệu để lưu bây giờ, bây giờ tôi sử dụng một mã thông báo / lexer / trình phân tích cú pháp phù hợp với cú pháp rõ ràng. Yêu thích của tôi làm tất cả / bất kỳ, sạch sẽ + có thể tự tối ưu hóa. Tôi đã học được cách khó khăn, và trong nhiều năm, rằng một chút kỷ luật tự giác khi bắt đầu có nghĩa là ít nỗ lực hơn sau này. Một regex là một khoảnh khắc trên bàn phím, và cả đời trên cau mày.
AndrewC

44

Biểu thức chính quy cho phép bạn viết một máy trạng thái hữu hạn tùy chỉnh (FSM) một cách gọn nhẹ, để xử lý một chuỗi đầu vào. Có ít nhất hai lý do tại sao sử dụng biểu thức chính quy là khó:

  • Phát triển phần mềm trường học cũ bao gồm rất nhiều kế hoạch, mô hình giấy và suy nghĩ cẩn thận. Các biểu thức chính quy phù hợp với mô hình này rất tốt, bởi vì để viết một biểu thức hiệu quả đúng cách bao gồm rất nhiều nhìn chằm chằm vào nó, hình dung các đường dẫn của FSM.

    Các nhà phát triển phần mềm hiện đại thay vì sử dụng mã và sử dụng trình gỡ lỗi để thực hiện, để xem mã có đúng không. Biểu thức thông thường không hỗ trợ phong cách làm việc này rất tốt. Một "chạy" của một biểu thức chính quy thực sự là một hoạt động nguyên tử. Thật khó để quan sát thực hiện từng bước trong trình gỡ lỗi.

  • Thật quá dễ dàng để viết một biểu thức chính quy vô tình chấp nhận đầu vào nhiều hơn bạn dự định. Giá trị của biểu thức chính quy không thực sự khớp với đầu vào hợp lệ, nó không khớp với đầu vào không hợp lệ . Các kỹ thuật để thực hiện "kiểm tra âm tính" cho các biểu thức thông thường không phải là rất tiên tiến, hoặc ít nhất là không được sử dụng rộng rãi.

    Điều này đi đến điểm của các biểu thức thông thường là khó đọc. Chỉ cần nhìn vào một biểu thức thông thường, cần rất nhiều sự tập trung để hình dung tất cả các yếu tố đầu vào có thể bị từ chối, nhưng bị chấp nhận nhầm. Bạn đã bao giờ thử gỡ lỗi mã biểu thức chính quy của người khác chưa?

Nếu ngày nay có sự phản kháng đối với việc sử dụng các biểu thức chính quy giữa các nhà phát triển phần mềm, tôi nghĩ rằng điều đó chủ yếu là do hai yếu tố này.


4
Có nhiều công cụ tuyệt vời để gỡ lỗi regexps: regexbuddy.com
Jasper Bekkers

15
perl -Mre = debug -e "q [aabbcc] = ~ / ab * [cd] /"
Brad Gilbert

15
Tôi không nghĩ mình có thể nhìn thấy từ viết tắt "FSM" mà không nghĩ đến Flying Spaghetti Monster.
Shabbycoat

4
@Shabbycoat: Tôi không có ý xúc phạm. Nếu bạn muốn, bạn có thể sử dụng máy tự động hữu hạn xác định (DFA).
Bill Karwin

37

Mọi người có xu hướng nghĩ rằng biểu hiện thường xuyên là khó khăn; Nhưng đó là vì họ đang sử dụng chúng sai. Viết một lớp lót phức tạp mà không có bất kỳ bình luận, thụt lề hoặc đặt tên. (Bạn không nhồi nhét biểu thức SQL phức tạp của mình trong một dòng, không có nhận xét, thụt lề hoặc bí danh, phải không?). Vì vậy, có, đối với nhiều người, họ không có ý nghĩa.

Tuy nhiên, nếu công việc của bạn có bất cứ điều gì liên quan đến phân tích văn bản (gần như bất kỳ ứng dụng web nào ngoài đó ...) và bạn không biết biểu hiện thông thường, bạn sẽ mất công việc và bạn đang lãng phí thời gian của chính bạn và của bạn chủ nhân. Có những nguồn tài nguyên tuyệt vời ngoài kia để dạy cho bạn mọi thứ về chúng mà bạn cần biết, và hơn thế nữa.


2
Chà .. sự khác biệt là nhiều không gian có ý nghĩa trong regex, trong đó các ngôn ngữ khác chúng không có và đó là lý do tại sao chúng thường là một lớp lót (đôi khi bao bọc thành nhiều dòng :)
Rado

14
@Rado: Chẳng hạn, Perl có công cụ xsửa đổi cho các biểu thức chính khiến cho khoảng trắng bị bỏ qua. Điều này cho phép bạn đặt regex trên một vài dòng và thêm nhận xét.
Nathan Fellman

9
Tương tự như vậy Python có re.Xaka re.VERBOSE.
Craig McQueen

2
Tương tự như vậy, xsửa đổi trong tcl. Tôi tin rằng nó khá chuẩn vì tcl, không giống như các ngôn ngữ khác, không sử dụng PCRE.
slebetman

2
@AndrewC Đó là một trong những giải thích sai lầm nhất mà bài đăng này có thể nhận được.
Jasper Bekkers

28

Bởi vì họ thiếu công cụ học tập phổ biến nhất trong các IDE thường được chấp nhận: Không có Trình hướng dẫn Regex. Thậm chí không tự động hoàn thành. Bạn phải tự viết mã toàn bộ mọi thứ.


3
Sau đó, bạn đang sử dụng IDE sai ... Ngay cả trình soạn thảo văn bản của tôi cũng cung cấp gợi ý regex.
RèmDog

1
Bên cạnh đó, Expresso và The Regex Coach là những công cụ rất hữu ích để xây dựng các biểu thức thông thường.
Mun

22
Làm thế nào trên thế giới bạn sẽ tự động hoàn thành một biểu thức chính quy?
AmbroseChapel

3
EditPad Pro có cú pháp tô sáng cho regexes trong hộp tìm kiếm, nhưng tôi thấy nó khó chịu hơn là hữu ích, và tắt nó đi. Nhưng tôi đánh giá cao nó cho tôi biết khi tôi có dấu ngoặc chưa từng có; dấu ngoặc đơn đặc biệt có thể là một con gấu để theo dõi.
Alan Moore

2
@AmbroseChapel - Tôi là một vài năm muộn cho cuộc thảo luận này. Nhưng tôi đã tạo ra một cơ chế tự động hoàn thành tại regexhero.net/tester Nó được khởi xướng bởi các cấu trúc phổ biến bên trong dấu ngoặc tròn (), vuông []hoặc xoăn {}. Nó cũng sẽ làm việc với dấu gạch chéo ngược.
Steve Wortham


16

Tôi không nghĩ chúng gây tranh cãi.

Tôi cũng nghĩ rằng bạn đã trả lời câu hỏi của riêng mình, bởi vì bạn chỉ ra rằng thật ngớ ngẩn khi sử dụng chúng ở mọi nơi ( Không phải mọi thứ đều là ngôn ngữ thông thường 2 ) hoặc để tránh sử dụng chúng. Bạn, lập trình viên, phải đưa ra quyết định thông minh về việc khi nào các biểu thức chính quy sẽ giúp mã hoặc làm tổn thương nó. Khi phải đối mặt với một quyết định như vậy, hai điều quan trọng cần ghi nhớ là khả năng duy trì (ngụ ý khả năng đọc) và khả năng mở rộng.

Đối với những người đặc biệt ác cảm với họ, tôi đoán là họ chưa bao giờ học cách sử dụng chúng đúng cách. Tôi nghĩ rằng hầu hết những người chỉ dành vài giờ với một hướng dẫn tốt sẽ tìm ra họ và trở nên thông thạo rất nhanh. Đây là gợi ý của tôi về nơi bắt đầu:

http://docs.python.org/howto/regex

Mặc dù trang đó nói về các biểu thức thông thường trong ngữ cảnh của Python, tôi đã tìm thấy thông tin rất có thể áp dụng ở nơi khác. Có một vài điều cụ thể của Python, nhưng tôi tin rằng chúng được ghi chú rõ ràng và dễ nhớ.


2
Trang này dường như đã chuyển đến docs.python.org/howto/regex
Dominic K

@DMan Cảm ơn. Tôi sẽ chỉnh sửa câu trả lời của mình để phản ánh.
mã allyour

11

Các biểu thức chính quy là chuỗi các toán tử số học cho các số và tôi sẽ không xem chúng là tranh cãi. Tôi nghĩ rằng ngay cả một nhà hoạt động OO khá mạnh mẽ như tôi (người có xu hướng chọn các đối tượng khác trên chuỗi) sẽ khó lòng từ chối chúng.


7

Vấn đề là regexes có tiềm năng mạnh mẽ đến mức bạn có thể làm mọi thứ với chúng mà bạn nên sử dụng một cái gì đó khác biệt cho.

Một lập trình viên giỏi nên biết sử dụng chúng ở đâu, và ở đâu không. Ví dụ điển hình là phân tích các ngôn ngữ không thông thường (xem Quyết định liệu một ngôn ngữ có thường xuyên không ).

Tôi nghĩ rằng bạn không thể sai nếu ban đầu bạn tự giới hạn mình trong các biểu thức chính quy thực sự (không có phần mở rộng). Một số tiện ích mở rộng có thể làm cho cuộc sống của bạn dễ dàng hơn một chút, nhưng nếu bạn thấy điều gì đó khó diễn đạt như một regex thực sự , đây cũng có thể là một dấu hiệu cho thấy regex không phải là công cụ phù hợp.


5

Bạn gần như cũng có thể hỏi về lý do tại sao goto gây tranh cãi.

Về cơ bản, khi bạn nhận được rất nhiều sức mạnh "rõ ràng", mọi người có thể lạm dụng chúng trong các tình huống mà họ không phải là lựa chọn tốt nhất. Ví dụ, số người yêu cầu phân tích CSV hoặc XML hoặc HTML trong các biểu thức chính, làm tôi kinh ngạc. Đó là công cụ sai cho công việc. Nhưng một số người dùng vẫn khăng khăng sử dụng regexes.

Cá nhân, tôi cố gắng tìm phương tiện hạnh phúc đó - sử dụng các biểu thức chính cho những gì chúng tốt và tránh chúng khi chúng không tối ưu.

Lưu ý rằng regex vẫn có thể được sử dụng để phân tích CSV, XML, HTML, v.v. Nhưng thường không phải trong một regex duy nhất.


Chắc chắn bạn có thể phân tích bất kỳ định dạng nào trong một regex duy nhất, đó là sức mạnh của regexes, em yêu! Cho dù bạn có muốn làm điều đó hay không, là một vấn đề hoàn toàn khác.
Jasper

4

Tôi không nghĩ "gây tranh cãi" là từ đúng.

Nhưng tôi đã thấy hàng tấn ví dụ mà mọi người nói "biểu thức chính quy tôi cần để thực hiện một thao tác chuỗi như vậy là gì?" đó là những vấn đề XY.

Nói cách khác, họ đã bắt đầu từ giả định rằng một biểu thức chính là thứ họ cần, nhưng họ sẽ tốt hơn với một dấu tách (), một bản dịch như tr /// trong đó các ký tự được thay thế cho một ký tự khác, hoặc chỉ là một chỉ mục ().


4

Đây là một chủ đề thú vị.
Nhiều regexp người hâm mộ dường như nhầm lẫn giữa conciseness của công thức có hiệu quả.
Trên hết, một regrec đòi hỏi rất nhiều suy nghĩ tạo ra cho tác giả của nó một sự hài lòng lớn khiến nó trở nên hợp pháp ngay lập tức.

Nhưng ... regexps rất tiện lợi khi hiệu suất không phải là vấn đề và bạn cần xử lý nhanh chóng với đầu ra văn bản, ví dụ như Perl. Ngoài ra, trong khi hiệu suất một vấn đề, người ta có thể không muốn đánh bại thư viện regrec bằng cách sử dụng thuật toán tự chế có thể có lỗi hoặc kém hiệu quả hơn.

Ngoài ra, có một số lý do khiến regexps bị chỉ trích không công bằng, ví dụ

  • regrec không hiệu quả, bởi vì xây dựng đỉnh cao là không rõ ràng
  • một số lập trình viên "quên" chỉ biên dịch một lần regrec được sử dụng nhiều lần (như Mẫu tĩnh trong Java)
  • một số lập trình viên dùng thử chiến lược dùng thử và lỗi - hoạt động thậm chí ít hơn với regexps!

4

Điều tôi nghĩ là Learning Regex và việc duy trì regex trở nên không phổ biến, hầu hết các nhà phát triển đều lười biếng hoặc hầu hết họ dựa vào các thư viện bên ngoài để thực hiện phân tích cú pháp cho họ ... họ dựa vào google để trả lời và thậm chí hỏi trên các diễn đàn mã hoàn chỉnh cho vấn đề của họ. Nhưng khi thực hiện hoặc sửa đổi / duy trì một regex, họ chỉ đơn giản là thất bại.

Có một câu nói phổ biến "Bạn bè không cho phép bạn bè sử dụng Regex để phân tích cú pháp HTML"

Nhưng theo như tôi quan tâm, tôi đã tạo ra các trình phân tích cú pháp HTML hoàn chỉnh bằng Regex và tôi thấy bản thân mình rằng regex tốt hơn trong việc phân tích chuỗi html cả về tốc độ và trí nhớ (nếu bạn có một ý tưởng bạn cần đạt được gì :))


2
Tôi nghĩ thật thiếu sót khi viết ra hầu hết các nhà phát triển ... là lười biếng. Tôi sẽ nói rằng cú pháp rất khó hiểu, không trực quan và đầy những vấn đề, đối với người chưa bắt đầu, dẫn đến một rào cản cao để nhập cảnh. Vì lý do tương tự, Perl có tiếng xấu "đối với nhiều người, nhưng cũng là một ngôn ngữ rất mạnh mẽ. Nó giống như cố gắng đọc các biểu thức toán học trước khi bạn biết các ký hiệu. Thật khó khăn và các nhà phát triển phải thận trọng với thời gian để biết rằng họ sẽ nhận được lợi ích cho việc học cú pháp đó.
Chuyến đi Katastic

Bạn sẽ bỏ lỡ các trường hợp cạnh trong HTML vì HTML không phải là ngôn ngữ thông thường. Bạn an toàn nếu ý định của bạn là phân tích một tập hợp con đã biết của HTML
Boyang

2

Biểu hiện thường xuyên là một bí ẩn nghiêm trọng đối với rất nhiều người, bao gồm cả bản thân tôi. Nó hoạt động rất tốt nhưng nó giống như nhìn vào một phương trình toán học. Tôi rất vui khi báo cáo rằng cuối cùng ai đó đã tạo ra một vị trí hợp nhất của các hàm biểu thức chính quy khác nhau tại http://regexlib.com/ . Bây giờ nếu Microsoft chỉ tạo một lớp biểu thức chính quy sẽ tự động thực hiện nhiều thao tác phổ biến như loại bỏ các chữ cái hoặc lọc ngày.


2
Bạn đang thiếu điểm. Ý tưởng của regexes là bạn đầu tư một chút thời gian vào việc học chúng và khi bạn hoàn thành, bạn không còn cần một lớp học "đọc một ngày" kỳ diệu. Thay vào đó, phải mất rất ít nỗ lực regex cho họ. Hơn nữa, sẽ chỉ cần một nỗ lực nhỏ để viết một cái cho "yyyy / mm / dd" khi viết một cái cho "mm-dd-yyyy", hoặc thậm chí một cái cho "mm-yyyy / dd" (đã thắng sẽ không xảy ra thường xuyên, nhưng đó là một ví dụ về cách bạn có thể làm những việc mà một lớp phép thuật không bao giờ có thể ")
Jasper

1

Tôi tìm thấy biểu thức thường xuyên vô giá tại các thời điểm. Khi tôi cần thực hiện một số tìm kiếm "mờ" và có thể thay thế. Khi dữ liệu có thể thay đổi và có một sự ngẫu nhiên nhất định. Tuy nhiên, khi tôi cần thực hiện một tìm kiếm đơn giản và thay thế hoặc kiểm tra một chuỗi, tôi không sử dụng các biểu thức thông thường. Mặc dù tôi biết nhiều người làm, họ sử dụng nó cho mọi thứ. Đó là tranh cãi.

Nếu bạn muốn đặt một cái đinh trên tường, đừng dùng búa. Vâng, nó sẽ hoạt động, nhưng khi bạn lấy được búa, tôi có thể đặt 20 cái đinh vào tường.

Biểu thức thông thường nên được sử dụng cho những gì chúng được thiết kế cho, và không có gì ít hơn.


0

Trong khi tôi nghĩ regexes là một công cụ thiết yếu, điều khó chịu nhất về chúng là có nhiều cách triển khai khác nhau. Sự khác biệt nhỏ về cú pháp, sửa đổi và - đặc biệt là "lòng tham" có thể khiến mọi thứ thực sự hỗn loạn, đòi hỏi phải dùng thử và lỗi và đôi khi tạo ra các lỗi khó hiểu.


Làm thế nào để triển khai regex khác nhau trong cách tiếp cận của họ để phù hợp tối đa, điều mà tôi nghĩ rằng bạn đang gọi là Tham lam? Bạn có nghĩa là sự khác biệt giữa ngữ nghĩa ngoài cùng dài nhất so với dài nhất bên trái ? Đó là sự khác biệt duy nhất tôi biết; tức là, dù tham lam vấp ngã háo hức hay ngược lại .
tchrist

0

Trong một số trường hợp tôi nghĩ bạn PHẢI sử dụng chúng. Ví dụ để xây dựng một lexer.

Theo tôi, đây là quan điểm của những người có thể viết regrec và những người không (hoặc hầu như không). Tôi cá nhân điều này là một suy nghĩ tốt, ví dụ để xác thực đầu vào của một biểu mẫu, có thể là trong javascript để cảnh báo người dùng hoặc bằng ngôn ngữ phía máy chủ.


0

Tôi nghĩ rằng đó là một kỹ thuật ít được biết đến trong số các lập trình viên. Vì vậy, không có sự chấp nhận rộng rãi cho nó. Và nếu bạn có một người quản lý phi kỹ thuật để xem lại mã của bạn hoặc xem lại công việc của bạn thì một biểu thức thông thường là rất tệ. Bạn sẽ dành hàng giờ để viết một biểu thức chính quy hoàn hảo và bạn sẽ nhận được một vài điểm cho mô-đun nghĩ rằng anh ấy / cô ấy đã viết rất ít dòng mã. Ngoài ra, như đã nói ở nơi khác, đọc biểu thức chính quy là nhiệm vụ rất khó khăn.


1
Đọc biểu thức chính quy là nhiệm vụ khó khăn chỉ khi lập trình viên tạo ra chúng không sử dụng khoảng trắng, nhận xét, định danh chữ và số, và có lẽ cả chương trình con nhúng thông qua thực thi bị trì hoãn. Nói tóm lại, tất cả các kỹ thuật kỹ thuật phần mềm áp dụng cho lập trình chung cũng nên được tuân theo trong các biểu thức thông thường. Nếu những nguyên tắc này bị bỏ qua, thì người viết không tạo ra mã chuyên nghiệp.
tchrist

Tôi nghĩ rằng người quản lý của bạn không biết rằng "Người hùng thực sự của lập trình là người viết mã tiêu cực."
Rajeev

Nếu người quản lý của bạn sẽ yêu cầu bạn hoàn thành công việc với 3 dòng mã (bao gồm cả biểu thức chính quy), trong khi khen ngợi một số đồng nghiệp doofus đã thực hiện nó trong 900 dòng Trình biên dịch ... Tôi khuyên bạn nên tìm một công việc mới.
Phil Perry

0

Các hệ thống biểu thức chính quy như được sử dụng trong lex và yacc cho định nghĩa trình biên dịch là tốt, rất hữu ích và sạch sẽ. Trong các hệ thống này, các loại biểu thức được định nghĩa theo nghĩa khác. Đó là các biểu thức chính quy khổng lồ một lớp lót không thể đọc được, không thể đọc được thường thấy trong mã perl và sed (v.v.) gây tranh cãi '(rác).


-4

Việc sử dụng hợp lệ và bình thường tốt nhất cho regex là xác thực định dạng địa chỉ email.

Đó là một ứng dụng tốt của nó.

Tôi đã sử dụng các biểu thức thông thường vô số lần như một lần trong TextPad để xoa bóp các tệp phẳng, tạo các tệp csv, tạo các câu lệnh chèn SQL và đại loại như vậy.

Các biểu thức chính quy được viết tốt không nên quá chậm. Thông thường, các lựa chọn thay thế, như hàng tấn cuộc gọi đến Thay thế là các tùy chọn chậm hơn nhiều. Cũng có thể làm điều đó trong một lần.

Nhiều tình huống gọi cho các biểu thức chính xác thường xuyên và không có gì khác.

Thay thế các ký tự không in đặc biệt bằng các ký tự vô hại là một cách sử dụng tốt khác.

Tất nhiên tôi có thể tưởng tượng rằng có một số cơ sở mã hóa sử dụng quá mức các biểu thức chính quy gây bất lợi cho khả năng bảo trì. Tôi chưa bao giờ thấy điều đó bản thân mình. Tôi thực sự đã bị các nhà phê bình mã tránh khỏi việc không sử dụng các biểu thức thông thường đủ.


10
Kinh nghiệm cho thấy regex thực sự là một công cụ khá kém để xác thực định dạng địa chỉ email. Trình xác thực định dạng thực sự hoàn chỉnh được triển khai dưới dạng regex là một quái vật có hàng trăm ký tự, trong khi hầu hết các trình xác nhận "đủ tốt" ngắn mà hầu hết mọi người mất 5 phút để tạo sẽ từ chối các danh mục lớn có thể gửi được.
Dave Sherohman

Tôi nghe thấy anh bạn. Tôi đã nói về "đủ tốt" và trong khi lý thuyết lớn có thể lớn về mặt lý thuyết, hãy xem xét tỷ lệ phần trăm bảo hiểm bạn nhận được trong một biểu thức ngắn như vậy. Tôi cũng đã nhìn thấy sự quái dị, nhưng sự thay thế thanh lịch của bạn là gì?
Chris Morley

2
Tôi đã sử dụng một cái gì đó như \ w @ \ w +. \ W + để nhanh chóng tìm thấy địa chỉ email trong một thư mục lớn các tệp trong đó tốc độ là quan trọng và một vài thông tin sai hoặc phủ định sai là không quan trọng. Nhưng cách tốt nhất để xác nhận một địa chỉ email dường như là gửi email đến địa chỉ đó.
RossFovenant

Vâng gửi email thông số kỹ thuật địa chỉ là một stackoverflow
Nick Van Brunt

@Nick, @Dave: Xác thực địa chỉ thư không cần phải là một mớ hỗn độn khó chịu.
tchrist
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.