Dlaczego wyrażenia regularne są tak kontrowersyjne? [Zamknięte]


212

Podczas eksploracji wyrażeń regularnych (znanych również jako RegEx-es) istnieje wiele osób, które wydają się postrzegać wyrażenia regularne jako Świętego Graala. Coś, co wygląda na tak skomplikowane - po prostu musi być odpowiedzią na każde pytanie. Zwykle myślą, że każdy problem można rozwiązać za pomocą wyrażeń regularnych.

Z drugiej strony jest też wiele osób, które za wszelką cenę starają się unikać wyrażeń regularnych. Próbują znaleźć sposób na wyrażenie regularne i akceptują dodatkowe kodowanie, nawet jeśli wyrażenia regularne byłyby bardziej zwartym rozwiązaniem.

Dlaczego wyrażenia regularne są tak kontrowersyjne? Czy istnieją powszechne nieporozumienia dotyczące sposobu ich działania? Czy może być powszechne przekonanie, że wyrażenia regularne są na ogół powolne?


9
jeśli jest to dyskusja, to czy nie powinna być zamknięta? ale widzę tam prawdziwe pytanie, więc może tag dyskusji nie należy?
RCIX

6
Bez żartów. Podnosisz to i ludzie zaczynają szaleć tutaj.
Ryan Florence,

1
Ładne spostrzeżenie i sformułowanie w pytaniu!
imz - Ivan Zachharyaschev


Pytanie oparte jest na opinii, reguła powinna tu również obowiązywać (lub pytanie powinno zostać zredagowane, aby uzyskać precyzyjną odpowiedź). To powiedziawszy, zakładam, że kontrowersja wyrażeń regularnych pochodzi z nieprecyzyjności samouczków i instrukcji na ten temat. Przez większość czasu, jeśli nie przez cały czas, informacje są mieszane, a dodatkowo nie otrzymujemy wszystkich cech. Dodaj do tego niewłaściwego użycia języka, w końcu nauczysz się czegoś, co zauważy na drodze, że może to oznaczać coś innego. I wreszcie, specjalne znaki wyrażenia regularnego nie są ograniczone do jednego znaczenia, które dodaje więcej zamieszania.
intika

Odpowiedzi:


136

Nie sądzę, by ludzie sprzeciwiali się wyrażeniom regularnym, ponieważ są powolni, ale raczej dlatego, że trudno je czytać i pisać, a także trudne do poprawnego działania. Chociaż istnieją sytuacje, w których wyrażenia regularne zapewniają skuteczne, kompaktowe rozwiązanie problemu, czasami są one wykorzystywane w sytuacjach, w których lepiej jest zamiast tego użyć łatwej do odczytania, łatwej do utrzymania sekcji kodu.


2
I tak, wyrażenia regularne mogą być bardzo wolne w porównaniu do korzystania z prostych funkcji. I to nie tylko powolne, ale wydajność silnika wyrażeń regularnych może być całkowicie nieprzewidywalna w przypadku arbitralnych (dostarczanych przez użytkownika) danych wejściowych.
Pacerier,

1
Jeśli wiesz, jak działa wyrażenie regularne, nie stanowi to żadnego problemu.
Shiplu Mokaddim,

8
@pacerier, to nie są wolne wzory , to wolne silniki . Większość (nowoczesnych) silników wyrażeń regularnych jest nieodpowiednia dla złożonych wzorców (np. Wielu |lub .*), ponieważ używają maszyny stosu i śledzenia wstecznego. Dlatego musisz dokładnie dostroić swoje wyrażenia regularne w Perlu, Javie, Pythonie, Ruby… Starym stylu silniki wyrażeń regularnych ( grepna przykład) najpierw kompilują wzór do DFA. Następnie złożoność wzoru jest w dużej mierze nieistotna. Właśnie użyłem Java i grep dla tego samego tekstu i wzoru: 22min vs 2s. Oto nauka: swtch.com/~rsc/regexp/regexp1.html
hagello

122

Utrzymywanie regeksów w utrzymaniu

Znaczącym postępem w kierunku odszyfrowania wzorców zwanych wcześniej „wyrażeniami regularnymi” jest /xflaga wyrażeń regularnych Perla - czasami zapisywana(?x) po osadzeniu - która umożliwia spacje (łamanie linii, wcięcia) i komentarze. To znacznie poprawia czytelność, a tym samym łatwość konserwacji. Biała przestrzeń pozwala na dzielenie kognitywne, dzięki czemu można zobaczyć, z którymi grupami co.

Współczesne wzorce obsługują teraz zarówno relatywnie ponumerowane, jak i nazwane odwołania wsteczne. Oznacza to, że nie musisz już liczyć grup przechwytywania, aby dowiedzieć się, że potrzebujesz $4lub\7 . Pomaga to w tworzeniu wzorów, które można uwzględnić w kolejnych wzorach.

Oto przykład względnie numerowanej grupy przechwytywania:

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

A oto przykład lepszego podejścia do nazwanych chwytów:

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

Reguły gramatyczne

Co najważniejsze , te nazwane zrzuty można umieścić w (?(DEFINE)...)bloku, dzięki czemu można oddzielić deklarację od wykonania poszczególnych nazwanych elementów wzorców. To sprawia, że ​​zachowują się one jak podprogramy we wzorcu.
Dobry przykład tego rodzaju „wyrażenia gramatycznego” można znaleźć w tej i tej odpowiedzi . Wyglądają one bardziej jak deklaracja gramatyczna.

Jak to ostatnie przypomina:

… Upewnij się, że nigdy nie zapisujesz wzorów szumów linii. Nie musisz i nie powinieneś. Żaden język programowania nie może być utrzymany, który zabrania białych znaków, komentarzy, podprogramów lub identyfikatorów alfanumerycznych. Więc używaj tych wszystkich rzeczy w swoich wzorach.

Tego nie można przecenić. Oczywiście, jeśli nie użyjesz tych rzeczy w swoich wzorach, często stworzysz koszmar. Ale jeśli zrobić z nich korzystać, choć nie musisz.

Oto kolejny przykład nowoczesnego wzorca gramatycznego, ten do analizowania RFC 5322: użyj 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;

Czy to nie jest niezwykłe - i wspaniałe? Możesz wziąć gramatykę w stylu BNF i przetłumaczyć ją bezpośrednio na kod bez utraty podstawowej struktury!

Jeśli nowoczesne wzorce gramatyczne nadal nie są dla Ciebie wystarczające, genialny Regexp::Grammarsmoduł Damiana Conwaya oferuje jeszcze czystszą składnię, a także doskonałe debugowanie. Oto ten sam kod do analizowania przekształcenia RFC 5322 we wzorzec z tego modułu:

#!/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
    }
}

Jest wiele dobrych rzeczy w perlre podręcznika , ale te dramatyczne zmiany w podstawowych cech konstrukcyjnych regex są w żaden sposób ograniczone do Perl sam. Rzeczywiście pcrepattern podręcznika może być łatwiejszy do odczytu i obejmuje ten sam obszar.

Nowoczesne wzorce nie mają prawie nic wspólnego z prymitywnymi rzeczami, których nauczyłeś się w swojej klasie automatów skończonych.


9
TAK! TAK! Na koniec ktoś pokazuje świetny przykład tego, jak czytelne wyrażenia regularne mogą być za pomocą modyfikatora x. Nie mogę uwierzyć, jak niewiele osób wie, że istnieje, a co dopiero z niego korzystać.
Shabbyrobe

1
@Shabbyrobe: To nie tylko /x. Korzysta z wyrażeń gramatycznych, z (?&name)wewnętrznymi podprogramami wyrażeń regularnych, które naprawdę sprawiają, że to błyszczy.
tchrist

+1 Zawsze uczysz się czegoś nowego. Nie wiedziałem, że PCRE ma „fałszywy” warunek dla definicji.
NikiC

5
Python podobnie ma re.VERBOSEflagę.
Ślimak mechaniczny

3
Po prostu gunna, śmiało, powiedz, że wciąż jestem zdumiony długością, jaką ludzie zrobią, aby regex był użyteczny.
Slater Victoroff

68

Regeksy to świetne narzędzie, ale ludzie myślą: „Hej, co za wspaniałe narzędzie, użyję go do robienia X!” gdzie X jest czymś, do czego lepsze jest inne narzędzie (zwykle parser). Jest to standard przy użyciu młotka, w którym potrzebny jest problem ze śrubokrętem.


4
Pamiętaj tylko, że większość parserów - analizatorów elastycznych - wciąż używa wyrażeń regularnych do parsowania swoich rzeczy :-)
Jasper Bekkers

62
Powiedzenie, że parsery używają wyrażeń regularnych, jest jak powiedzenie, że parsery używają instrukcji przypisania. To nic nie znaczy, dopóki nie zobaczysz, jak są używane.
Chas. Owens,

24
Używanie RegEx, gdy parser jest lepszy, jest denerwujące. Używanie RegEx, gdy standardowe funkcje wyszukiwania lub zamiany języka w języku będą działać (i zwykle w czasie liniowym) jest po prostu niewybaczalne.
jmucchiello,

1
Zgadzam się, ponieważ RegEx musi być gniazdem wszystkich transakcji, koszty przetwarzania są ogromne. To, że użycie silnika RegEx wydaje się łatwe, nie oznacza, że ​​jest to lepsze rozwiązanie niż parser iteracyjny (próg zależny od programisty). Jeden z moich ulubionych przykładów PHP split($pattern,$string)kontra explode($delimiter,$string)- na szczęście ten pierwszy się deprecjonuje, ale wiele kodu używało tego pierwszego, gdy potrzebowały tylko mocy późniejszego. Zrozumiałe, RegEx zapewnia łatwe narzędzie do robienia pewnych rzeczy, ale chyba, że ​​potrzebujesz pełnej mocy wyrażeń regularnych
Rudu

4
Analizatory leksykalne mogą rzeczywiście używać wyrażeń regularnych. Są one również znane jako tokenizery, ale nie są analizatorami składniowymi (lub analizatorami składni). Aby odczytać wystarczająco skomplikowany ciąg, należy użyć tokenizera do odczytania łańcucha jako tokena (być może z wyrażeniami regularnymi, a może nie, w zależności od tokenizera). Tokeny te należy następnie przekazać do analizatora składni, który przetworzy je zgodnie z regułami gramatycznymi, które zdecydowanie nie są wyrażeniami regularnymi.
Axel

53

Prawie wszyscy, których znam, którzy regularnie używają wyrażeń regularnych (zamierzone słowa kluczowe) pochodzą z uniksowego środowiska, w którym używają narzędzi, które traktują RE jako najwyższej klasy konstrukcje programistyczne, takie jak grep, sed, awk i Perl. Ponieważ prawie nie ma narzutu składniowego, aby użyć wyrażenia regularnego, ich wydajność znacznie wzrasta.

Natomiast programiści używający języków, w których RE są biblioteką zewnętrzną, zwykle nie zastanawiają się, co wyrażenia regularne mogą przynieść do tabeli. „Koszt czasu” programisty jest tak wysoki, że albo a) RE nigdy nie pojawiły się w ramach szkolenia, lub b) nie „myślą” w kategoriach RE i wolą polegać na bardziej znanych wzorcach.


11
Tak, nigdy nie wybaczyłem Pythonowi, że używa wyrażeń regularnych przy użyciu biblioteki. Myślę, że to czystość nad zdrowiem psychicznym.
slikts

7
Pochodzę z uniksowego tła, używałem ładowań sed, awk i perl i oczywiście robiłem dużo greppingu, ale wiem, że kiedy użyję wyrażenia regularnego, to hack tylko do zapisu, którego nienawidzę utrzymywać. Jest dobry dla skryptów powłoki / jednorazowych, ale do prawdziwej pracy, do wszystkiego, co nie jest tylko pobieraniem danych do zapisania, teraz używam odpowiedniego tokenizera / lexera / parsera z przejrzystą składnią. Mój ulubiony robi wszystko / dowolnie, czysto + może sam się zoptymalizować. Nauczyłem się na własnej skórze i przez wiele lat odrobina samodyscypliny na początku oznacza mniej wysiłku później. Wyrażenie regularne to chwila na klawiaturze i całe życie na twarzy.
AndrewC,

44

Wyrażenia regularne pozwalają napisać niestandardową maszynę skończoną (FSM) w kompaktowy sposób, aby przetworzyć ciąg danych wejściowych. Istnieją co najmniej dwa powody, dla których używanie wyrażeń regularnych jest trudne:

  • Oldschoolowe tworzenie oprogramowania wymaga planowania, modeli papierowych i dokładnego przemyślenia. Wyrażenia regularne bardzo dobrze pasują do tego modelu, ponieważ prawidłowe napisanie skutecznego wyrażenia wymaga dużo wpatrzenia się w niego, wizualizacji ścieżek FSM.

    Współcześni programiści woleliby raczej wykuć kod i użyć debuggera do wykonania zadania, aby sprawdzić, czy kod jest poprawny. Wyrażenia regularne nie obsługują tego stylu pracy zbyt dobrze. Jeden „ciąg” wyrażenia regularnego jest w rzeczywistości operacją atomową. Trudno zaobserwować stopniowe wykonywanie w debuggerze.

  • Zbyt łatwo jest napisać wyrażenie regularne, które przypadkowo akceptuje więcej danych wejściowych, niż zamierzają. Wartość wyrażenia regularnego nie jest tak naprawdę zgodna z prawidłowymi danymi wejściowymi, ale nie może być zgodna z nieprawidłowymi danymi wejściowymi . Techniki przeprowadzania „testów ujemnych” dla wyrażeń regularnych nie są bardzo zaawansowane lub przynajmniej nie są szeroko stosowane.

    Do tego stopnia, że ​​wyrażenia regularne są trudne do odczytania. Samo spojrzenie na wyrażenie regularne wymaga dużej koncentracji, aby wizualizować wszystkie możliwe dane wejściowe, które należy odrzucić, ale są błędnie akceptowane. Czy kiedykolwiek próbowałeś debugować kod wyrażenia regularnego innej osoby ?

Jeśli dzisiaj wśród programistów występuje opór przed używaniem wyrażeń regularnych, myślę, że wynika to głównie z tych dwóch czynników.


4
Istnieją doskonałe narzędzia do debugowania wyrażeń
Jasper Bekkers

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

15
Nie sądzę, żebym kiedykolwiek widział akronim „FSM” bez myślenia o Flying Spaghetti Monster.
Shabbyrobe

4
@Shabbyrobe: Nie chcę obrażać. Jeśli chcesz, możesz użyć deterministycznego automatu skończonego (DFA).
Bill Karwin

37

Ludzie myślą, że wyrażenia regularne są trudne; ale to dlatego, że źle ich używają. Pisanie złożonych jedno-liniowych tekstów bez komentarzy, wcięć i nazwanych ujęć. (Nie wciskasz złożonego wyrażenia SQL w jednym wierszu, bez komentarzy, wcięć i aliasów, prawda?). Tak, dla wielu ludzi nie mają sensu.

Jeśli jednak Twoja praca ma coś wspólnego z analizowaniem tekstu (z grubsza jakąkolwiek aplikacją internetową ...) i nie znasz wyrażeń regularnych, ssiesz swoją pracę i marnujesz swój czas i swoje pracodawca. Istnieją doskonałe zasoby , aby nauczyć Cię wszystkiego na ich temat, o których kiedykolwiek będziesz musiał wiedzieć, i wiele więcej.


2
Cóż ... różnica polega na tym, że wiele spacji ma znaczenie w wyrażeniu regularnym, gdzie w innych językach nie mają i dlatego zwykle są to jedne linijki (które czasami zawijają się w wiele wierszy :)
Rado

14
@Rado: Na przykład Perl ma xmodyfikator wyrażeń regularnych, który powoduje ignorowanie białych znaków. Umożliwia to umieszczenie wyrażenia regularnego w kilku wierszach i dodawanie komentarzy.
Nathan Fellman

9
Podobnie Python ma re.Xaka re.VERBOSE.
Craig McQueen

2
Podobnie xmodyfikator w tcl. Uważam, że jest to dość standardowe, ponieważ tcl, w przeciwieństwie do innych języków, nie używa PCRE.
slebetman

2
@AndrewC To jedna z najpoważniejszych błędnych interpretacji tego wpisu.
Jasper Bekkers

28

Ponieważ brakuje najpopularniejszego narzędzia do nauki w powszechnie akceptowanych IDE: nie ma Kreatora Regex. Nawet autouzupełnianie. Musisz sam wszystko zakodować.


3
W takim razie używasz niewłaściwego IDE ... Nawet mój edytor tekstu zawiera wskazówki wyrażeń regularnych.
CurtainDog

1
Na marginesie, Expresso i The Regex Coach są bardzo przydatnymi narzędziami do konstruowania wyrażeń regularnych.
Mun

22
Jak, u licha, automatycznie uzupełniałbyś wyrażenie regularne?
AmbroseChapel

3
EditPad Pro ma podświetlanie składni wyrażeń regularnych w polu wyszukiwania, ale uważam, że jest to bardziej denerwujące niż pomocne, i wyłączam je. Ale bardzo to doceniam, dając mi znać, gdy mam niedopasowane nawiasy; Zwłaszcza nawiasy mogą być niedźwiedziem do śledzenia.
Alan Moore,

2
@AmbroseChapel - spóźniłem się o kilka lat do tej dyskusji. Ale stworzyłem mechanizm autouzupełniania na regexhero.net/tester Jest on inicjowany przez popularne konstrukcje w nawiasach okrągłych (), kwadratowych []lub kręconych {}. Działa również z odwrotnym ukośnikiem.
Steve Wortham


16

Nie sądzę, żeby były tak kontrowersyjne.

Myślę również, że odpowiedziałeś na swoje własne pytanie, ponieważ wskazujesz, jak głupio byłoby używać ich wszędzie ( nie wszystko to zwykły język 2 ) lub w ogóle ich unikać. Ty, programista, musisz podjąć inteligentną decyzję, kiedy wyrażenia regularne pomogą kodowi lub go zranią. W obliczu takiej decyzji dwie ważne rzeczy, o których należy pamiętać, to łatwość utrzymania (co oznacza czytelność) i rozszerzalność.

Dla tych, którzy są im szczególnie niechętni, domyślam się, że nigdy nie nauczyli się ich właściwie używać. Myślę, że większość ludzi, którzy spędzą zaledwie kilka godzin na przyzwoitym samouczku, zrozumie je i bardzo szybko zacznie mówić. Oto moja sugestia, od czego zacząć:

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

Chociaż ta strona mówi o wyrażeniach regularnych w kontekście Pythona, zauważyłem, że informacje te są bardzo przydatne gdzie indziej. Jest kilka rzeczy specyficznych dla Pythona, ale uważam, że są one wyraźnie odnotowane i łatwe do zapamiętania.



@DMan Thanks. Przeredaguję swoją odpowiedź, aby odzwierciedlić.
allyourcode

11

Wyrażenia regularne odnoszą się do ciągów znaków, którymi są operatory arytmetyczne do liczb, i nie uważałbym ich za kontrowersyjne. Myślę, że nawet dość apodyktyczny działacz OO , taki jak ja (który miałby tendencję do wybierania innych obiektów zamiast strun), byłby trudny do odrzucenia.


7

Problem polega na tym, że wyrażenia regularne są potencjalnie tak potężne, że możesz z nimi robić różne rzeczy, do których powinieneś użyć czegoś innego.

Dobry programista powinien wiedzieć, gdzie ich używać, a gdzie nie. Typowym przykładem jest parsowanie języków nieregularnych (zobacz Decydowanie, czy język jest prawidłowy ).

Myślę, że nie możesz się pomylić, jeśli najpierw ograniczysz się do prawdziwych wyrażeń regularnych (bez rozszerzeń). Niektóre rozszerzenia mogą uczynić swoje życie trochę łatwiejsze, ale jeśli znajdziesz coś trudno wyrazić jako prawdziwego regex, to może okazać się wskazanie, że regex nie jest odpowiednim narzędziem.


5

Równie dobrze możesz zapytać, dlaczego goto są kontrowersyjne.

Zasadniczo, kiedy masz tyle „oczywistej” mocy, ludzie są skłonni do nadużywania ich w sytuacjach, w których nie są najlepszym rozwiązaniem. Na przykład liczba osób, które proszą o parsowanie CSV, XML lub HTML w wyrażeniach regularnych, zaskakuje mnie. To nieodpowiednie narzędzie do pracy. Ale niektórzy użytkownicy i tak nalegają na stosowanie wyrażeń regularnych.

Osobiście staram się znaleźć to szczęśliwe medium - używaj wyrażeń regularnych do tego, do czego są dobre, i unikaj ich, gdy nie są optymalne.

Pamiętaj, że wyrażenia regularne mogą być nadal używane do analizowania plików CSV, XML, HTML itp. Ale zwykle nie w jednym wyrażeniu regularnym.


Pewnie, że możesz parsować dowolny z tych formatów w jednym wyrażeniu regularnym, to jest siła wyrażeń regularnych, kochanie! To, czy chcesz to zrobić, to zupełnie inna sprawa.
Jasper

4

Nie sądzę, by „kontrowersyjne” było właściwym słowem.

Ale widziałem mnóstwo przykładów, w których ludzie mówią „jakie jest regularne wyrażenie, że muszę wykonywać takie i takie manipulacje ciągiem znaków?” które są problemami XY.

Innymi słowy, zaczęli od założenia, że ​​regex jest tym, czego potrzebują, ale lepiej byłoby z split (), tłumaczeniem takim jak tr /// perla, w którym znaki są zastępowane jeden za drugim, lub tylko indeks ().


4

To interesujący temat.
Wielu miłośników wyrażeń regularnych wydaje się mylić zwięzłość formuły z wydajnością.
Co więcej, wyrażenie regularne, które wymaga wiele przemyślenia, daje autorowi ogromną satysfakcję, dzięki czemu jest od razu uzasadnione.

Ale ... wyrażenia regularne są tak wygodne, gdy wydajność nie stanowi problemu i musisz szybko poradzić sobie z tekstem, na przykład w Perlu. Ponadto, podczas gdy wydajność jest problemem, można nie próbować bić biblioteki regexp za pomocą domowego algorytmu, który może być wadliwy lub mniej wydajny.

Poza tym istnieje wiele powodów, dla których wyrażenia regularne są niesprawiedliwie krytykowane, na przykład

  • Wyrażenie regularne nie jest wydajne, ponieważ zbudowanie pierwszego nie jest oczywiste
  • niektórzy programiści „zapominają” o kompilacji tylko raz wyrażenia regularnego do wielokrotnego użycia (jak statyczny wzorzec w Javie)
  • niektórzy programiści wybierają strategię prób i błędów - działa jeszcze mniej z regexps!

4

To, co myślę, to nauka regexu i utrzymywanie wyrażeń regularnych w niepopularnych, większość programistów jest leniwa lub większość z nich polega na bibliotekach zewnętrznych, aby zrobić dla nich analizę ... polegają na wyszukiwarce Google, a nawet pytają na forach pełny kod ich problemu. Ale jeśli chodzi o wdrożenie lub modyfikację / utrzymanie wyrażenia regularnego, po prostu zawodzą.

Istnieje popularne powiedzenie „Znajomi nie pozwalają znajomym używać Regex do analizowania HTML”

Ale jeśli o mnie chodzi, stworzyłem pełne parsery HTML przy użyciu Regex i uważam, że regex lepiej parsuje ciągi HTML zarówno pod względem szybkości, jak i pamięci (jeśli masz pomysł, co masz osiągnąć :))


2
Myślę, że nieuczciwe jest odpisywanie większości programistów ... jako leniwych. Powiedziałbym, że składnia jest bardzo tajemnicza, nieintuicyjna i pełna błędów, dla niezainicjowanych, co prowadzi do wysokiej bariery wejścia. Z tego samego powodu Perl ma dla wielu „złą” reputację, ale jest również bardzo potężnym językiem. To tak, jakbyś próbował czytać wyrażenia matematyczne, zanim poznasz symbole. Jest to zniechęcające, a programiści muszą zachować rozsądek, aby wiedzieć, że uzyskają korzyści z nauki tej składni.
Katastic Voyage

Państwo będzie przegap przypadków brzegowych w HTML, ponieważ HTML nie jest język regularny. Jesteś bezpieczny, jeśli zamierzasz przeanalizować znany podzbiór HTML
Boyang

2

Wyrażenia regularne są poważną tajemnicą dla wielu ludzi, w tym dla mnie. Działa świetnie, ale to tak, jakby patrzeć na równanie matematyczne. Z przyjemnością informuję, że ktoś w końcu stworzył skonsolidowaną lokalizację różnych funkcji wyrażeń regularnych na http://regexlib.com/ . Teraz, jeśli Microsoft utworzy tylko klasę wyrażeń regularnych, która automatycznie wykona większość typowych czynności, takich jak eliminacja liter lub filtrowanie dat.


2
Nie rozumiesz sedna sprawy. Idea wyrażeń regularnych polega na tym, że poświęcasz trochę czasu na ich naukę, a kiedy skończysz, nie potrzebujesz już magicznej klasy „czytaj randkę”. Zamiast tego wymaga bardzo niewielkiego wysiłku wyrażenia regularnego. Co więcej, napisanie jednego dla „rrrr / mm / dd” zajmuje tyle samo wysiłku, co napisanie jednego dla „mm-dd-rrrr”, a nawet jednego dla „mm-rrrr / dd” (który wygrał zdarza się często, ale jest to przykład tego, jak możesz robić rzeczy, których magiczna klasa nigdy nie potrafi ”).
Jasper

1

Czasami uważam, że wyrażenia regularne są bezcenne. Kiedy muszę wykonać pewne „rozmyte” wyszukiwania i być może zastąpię je. Gdy dane mogą się różnić i mieć pewną losowość. Jednak gdy muszę wykonać proste wyszukiwanie i zamienić lub sprawdzić ciąg znaków, nie używam wyrażeń regularnych. Chociaż znam wielu ludzi, którzy to robią, używają go do wszystkiego. To jest kontrowersja.

Jeśli chcesz umieścić hals w ścianie, nie używaj młotka. Tak, zadziała, ale zanim zdobędziesz młot, mógłbym włożyć 20 haczyków w ścianę.

Wyrażeń regularnych należy używać do tego, do czego zostały zaprojektowane, i nic więcej.


0

Chociaż myślę, że wyrażenia regularne są niezbędnym narzędziem, najbardziej denerwujące jest to, że istnieją różne implementacje. Nieznaczne różnice w składni, modyfikatorach, a zwłaszcza „chciwości” mogą sprawić, że wszystko stanie się naprawdę chaotyczne, wymagające prób i błędów, a czasem generowania zagadkowych błędów.


czym różnią się implementacje wyrażeń regularnych w podejściu do maksymalnego dopasowania, które, jak myślę, nazywasz „chciwością”? Czy masz na myśli różnicę między semantyką od lewej do najdłuższej a od najdłuższej z lewej ? To jedyna różnica, o której wiem; tzn. czy chciwość przebija zapał lub odwrotnie .
tchrist

0

W niektórych przypadkach myślę, że MUSISZ ich użyć. Na przykład, aby zbudować leksykon.

Moim zdaniem jest to punkt widzenia ludzi, którzy potrafią pisać wyrażenia regularne i ludzi, którzy nie (lub prawie nie). Osobiście uważam, że dobrym pomysłem jest na przykład sprawdzenie poprawności formularza, czy to w javascript, aby ostrzec użytkownika, czy w języku po stronie serwera.


0

Myślę, że jest to mniej znana technika wśród programistów. Zatem nie ma na to szerokiej akceptacji. A jeśli masz nietechnicznego managera do przeglądu kodu lub pracy, wyrażenie regularne jest bardzo złe. Spędzisz godziny na pisaniu idealnego wyrażenia regularnego i dostaniesz niewiele ocen za moduł, myśląc, że napisał tak mało wierszy kodu. Ponadto, jak powiedziano w innym miejscu, czytanie wyrażeń regularnych jest bardzo trudnym zadaniem.


1
Czytanie wyrażeń regularnych jest trudnym zadaniem tylko wtedy, gdy programista, który je utworzył, nie użył białych znaków, komentarzy, identyfikatorów alfanumerycznych, a być może również wbudowanych podprogramów poprzez opóźnione wykonanie. Krótko mówiąc, wszystkie techniki inżynierii oprogramowania mające zastosowanie do programowania ogólnego powinny być również stosowane w wyrażeniach regularnych. Jeśli te zasady zostaną zignorowane, autor nie będzie tworzył profesjonalnego kodu.
tchrist

Myślę, że twój menedżer nie wie, że „Prawdziwym bohaterem programowania jest ten, który pisze negatywny kod”.
Rajeev

Jeśli twój menadżer zamierza cię rzucić za wykonanie zadania za pomocą 3 linii kodu (w tym wyrażeń regularnych), chwaląc jakiegoś współpracownika doofus, który zrobił to w 900 liniach Assemblera ... Sugeruję znalezienie nowej pracy.
Phil Perry

0

Przyzwoite systemy wyrażeń regularnych, takie jak używane w lex i yacc do definicji kompilatora, są dobre, bardzo przydatne i czyste. W tych systemach typy wyrażeń są zdefiniowane w kategoriach innych. To ohydne zniekształcone, nieczytelne gigantyczne wyrażenia regularne z jednym wierszem, powszechnie spotykane w kodzie perl i sed (itp.), Które są „kontrowersyjne” (śmieci).


-4

Najlepsze prawidłowe i normalne użycie wyrażenia regularnego to sprawdzanie poprawności formatu adresu e-mail.

To dobre zastosowanie.

Używałem wyrażeń regularnych niezliczoną ilość razy jako jednorazowy efekt w TextPad do masowania płaskich plików, tworzenia plików csv, tworzenia instrukcji wstawiania SQL i tego typu rzeczy.

Dobrze napisane wyrażenia regularne nie powinny być zbyt wolne. Zwykle alternatywy, takie jak mnóstwo wezwań do zamiany, są znacznie wolniejszymi opcjami. Równie dobrze może to zrobić za jednym razem.

Wiele sytuacji wymaga wyrażeń regularnych i nic więcej.

Kolejnym dobrym zastosowaniem jest zastąpienie specjalnych znaków niedrukowalnych znakami nieszkodliwymi.

Mogę oczywiście wyobrazić sobie, że istnieją pewne podstawy kodowe, które nadużywają wyrażeń regularnych ze szkodą dla łatwości obsługi. Sam nigdy tego nie widziałem. Recenzenci kodu naprawdę mnie uprzedzili za to, że nie używają wystarczająco wyrażeń regularnych.


10
Doświadczenie pokazuje, że wyrażenia regularne są w rzeczywistości dość słabym narzędziem do sprawdzania poprawności formatu adresu e-mail. Naprawdę kompletny walidator formatu zaimplementowany jako regex to potworność składająca się z kilkuset znaków, podczas gdy większość krótszych „wystarczająco dobrych” walidatorów, których utworzenie zajmuje większość ludzi, odrzuca duże kategorie prawidłowych, możliwych do dostarczenia adresów.
Dave Sherohman

Słyszę, stary. Mówiłem o „wystarczająco dobrym” i chociaż teoretycznie duże pokosy mogą być duże, weź pod uwagę procent pokrycia, jaki otrzymujesz w tak krótkim wyrazie. Ja też widziałem potworność, ale jaka jest twoja elegancka alternatywa?
Chris Morley,

2
Użyłem czegoś takiego jak \ w @ \ w +. \ W +, aby szybko znaleźć adres e-mail w ogromnym katalogu plików, w których szybkość była ważna, a kilka fałszywych trafień lub fałszywych negatywów nie było ważne. Ale najlepszym sposobem na sprawdzenie adresu e-mail wydaje się wysłanie na niego wiadomości e-mail.
RossFabricant

Tak, e-mail, specyfikacja adresu to paskudny bałagan stackoverflow.com/questions/611775/…
Nick Van Brunt

@Nick, @Dave: Sprawdzanie poprawności adresu e-mail nie musi być nieprzyjemnym bałaganem.
tchrist
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.