Jaka jest różnica między nawiasami kwadratowymi a nawiasami w wyrażeniu regularnym?


101

Oto wyrażenie regularne, które utworzyłem do użycia w JavaScript:

var reg_num = /^(7|8|9)\d{9}$/

Oto kolejny zasugerowany przez członka mojego zespołu.

var reg_num = /^[7|8|9][\d]{9}$/

Zasada polega na sprawdzeniu numeru telefonu:

  • Powinien zawierać tylko dziesięć cyfr.
  • Pierwsza liczba powinna być dowolną z 7, 8 lub 9.

Odpowiedzi:


124

Te wyrażenia regularne są równoważne (w celu dopasowania):

  • /^(7|8|9)\d{9}$/
  • /^[789]\d{9}$/
  • /^[7-9]\d{9}$/

Wyjaśnienie:

  • (a|b|c)jest wyrażeniem regularnym „LUB” i oznacza „a lub b lub c”, chociaż obecność nawiasów, niezbędna dla LUB, również obejmuje cyfrę. Aby być ściśle równoważnym, należałoby zakodować, (?:7|8|9)że jest to grupa nieprzechwytywana .

  • [abc]to „klasa znaków”, co oznacza „dowolny znak z a, b lub c” (klasa znaków może używać zakresów, np. [a-d]= [abcd])

Powodem, dla którego te wyrażenia regularne są podobne, jest to, że klasa znaków jest skrótem dla „lub” (ale tylko dla pojedynczych znaków). Na przemian możesz również zrobić coś takiego, (abc|def)co nie przekłada się na klasę postaci.


30
(7|8|9)i [789]nie są równoważne, ponieważ pierwsze to przechwytywanie, drugie nie. (?:7|8|9)byłoby równoważne z drugiej strony (myślę, że wiesz, że oczywiście ...).
hochl

Widzę ten regex: [<<|>>|\]\]|\[\[]. Ze względu na kontekst wiem, że wyrażenie regularne próbuje dopasować <<lub >>lub [[lub ]]. Ale z tego, co powiedziałeś, powinno pasować <lub >lub [lub ]. Jeśli użyjesz |między [], czy nawiasy zachowują się inaczej?
Daniel Kaplan,

1
@DanielKaplan nie używa się |w klasie znaków [...], chyba że chcesz dopasować samą kreskę . Również powielanie znaków w klasie znaków nie daje żadnego efektu - klasa postaci to lista znaków, która będzie pasować dokładnie do jednego z nich. Domyślam się, że chcesz mieć grupę , która używa normalnych okrągłych nawiasów:(<<|>>|\]\]|\[\[)
Bohemian

57

Rada twojego zespołu jest prawie słuszna, z wyjątkiem popełnionego błędu. Kiedy dowiesz się dlaczego, nigdy tego nie zapomnisz. Spójrz na ten błąd.

/^(7|8|9)\d{9}$/

Co to oznacza:

  • ^i $oznacza zakotwiczone dopasowania, co oznacza, że ​​podwzór między tymi kotwicami jest całym dopasowaniem. Ciąg będzie pasował tylko wtedy, gdy podwzór będzie pasował do całości, a nie tylko do sekcji.
  • ()oznacza grupę przechwytującą .
  • 7|8|9oznacza dopasowując jeden z 7, 8lub 9. Robi to z naprzemiennymi zmianami , co |robi operator potoku - naprzemiennie między zmianami. Powoduje to cofanie się między zmianami: Jeśli pierwsza zmiana nie jest dopasowana, silnik musi powrócić, zanim położenie wskaźnika przesunięte podczas dopasowania zmiany, aby kontynuować dopasowywanie następnej zmiany; Podczas gdy klasa postaci może postępować sekwencyjnie. Zobacz to dopasowanie w silniku wyrażeń regularnych z wyłączonymi optymalizacjami:
Pattern: (r|f)at
Match string: carat

alternacje

Pattern: [rf]at
Match string: carat

klasa

  • \d{9}pasuje do dziewięciu cyfr. \dto skrótowy metaznak, który pasuje do wszystkich cyfr.
/^[7|8|9][\d]{9}$/

Zobacz, co to robi:

  • ^i $oznacza również zakotwiczone dopasowania.
  • [7|8|9]to klasa postaci . Wszelkie znaki z listy 7, |, 8, |, lub 9mogą być dopasowane, tak więc |dodano niepoprawnie. To pasuje bez cofania.
  • [\d]to klasa znaków, która zamieszkuje metaznak \d. Nawiasem mówiąc, połączenie użycia klasy znaków i pojedynczego metaznaku jest złym pomysłem, ponieważ warstwa abstrakcji może spowolnić dopasowanie, ale jest to tylko szczegół implementacji i dotyczy tylko kilku implementacji wyrażeń regularnych. JavaScript nie jest jednym z nich, ale sprawia, że ​​podwzór jest nieco dłuższy.
  • {9} wskazuje, że poprzednia pojedyncza konstrukcja została powtórzona w sumie dziewięć razy.

Optymalnym wyrażeniem regularnym jest /^[789]\d{9}$/, ponieważ /^(7|8|9)\d{9}$/przechwytuje niepotrzebnie, co powoduje spadek wydajności w większości implementacji wyrażeń regularnych (tak się składa, że ​​pytanie używa słowa kluczowego varw kodzie, prawdopodobnie jest to JavaScript). Sposób użyciaktóry działa na PCRE dla dopasowania preg, zoptymalizuje brak cofania, jednak nie jesteśmy w PHP, więc używanie klas []zamiast naprzemiennych |daje premię za wydajność, ponieważ dopasowanie nie cofa się, a zatem zarówno mecze, jak i kończą się niepowodzeniem szybciej niż użycie twojego poprzednie wyrażenie regularne.


6
tylko z zainteresowania, z jakiego programu jest ten zrzut ekranu?
Mr Mystery Guest

12

Pierwsze 2 przykłady działają zupełnie inaczej, jeśli zastępujesz je czymś. Jeśli pasujesz w tym:

str = str.replace(/^(7|8|9)/ig,''); 

zastąpiłbyś 7, 8 lub 9 pustym ciągiem.

Jeśli pasujesz do tego

str = str.replace(/^[7|8|9]/ig,''); 

można wymienić 7lub 8lub 9lub pionowego BAR !!!! przez pusty ciąg.

Po prostu odkryłem to na własnej skórze.


6
Witamy w SO! Zastąpienie lub dopasowanie, to po prostu błąd. Wiele osób popełnia ten błąd i zwykle udaje im się to - czasami przez lata - ponieważ ich ciągi wejściowe nigdy nie zawierają potoku ( |).
Alan Moore
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.