Яка різниця між квадратними дужками і круглими дужками в регулярному виразі?


101

Ось регулярний вираз, який я створив для використання в JavaScript:

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

Ось ще одна, запропонована членом моєї команди.

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

Правило - перевірити номер телефону:

  • Він повинен бути лише з десяти чисел.
  • Перше число повинно бути будь-яким із 7, 8 або 9.

Відповіді:


124

Ці регекси еквівалентні (для відповідності):

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

Пояснення:

  • (a|b|c)є регулярним виразом "АБО" і означає "a або b або c", хоча наявність дужок, необхідних для АБО, також фіксує цифру. Щоб бути абсолютно рівнозначним, ви б кодували його, (?:7|8|9)щоб зробити групу, яка не захоплює.

  • [abc]є "класом символів", що означає "будь-який символ з а, b або c" (клас символів може використовувати діапазони, наприклад [a-d]= [abcd])

Причина цих регексів схожа в тому, що клас символів - це скорочення для "або" (але лише для окремих символів). У чергуванні ви також можете зробити щось подібне, (abc|def)що не перекладається на клас символів.


30
(7|8|9)і [789]не є рівнозначними, бо перше захоплює, друге - ні. (?:7|8|9)З іншого боку, це було б рівнозначно (я думаю, ви це знаєте, звичайно ...).
hochl

Я бачу це регулярний вираз: [<<|>>|\]\]|\[\[]. З контексту, я знаю , що регулярний вираз намагається відповідати <<або >>або [[або ]]. Але від того, що ви сказали, це повинно бути відповідність <або >або [або ]. Якщо ви використовуєте |між [], чи дужки поводяться по-різному?
Даніель Каплан

1
@DanielKaplan не використовувати |в класах символів [...], якщо ви не хочете відповідати самому символу труби. Також дублювання символів у класі символів не впливає - клас символів - це список символів і відповідатиме точно одному з них. Я здогадуюсь, що ви хочете отримати групу , яка використовує звичайні круглі дужки:(<<|>>|\]\]|\[\[)
богемський

57

Поради вашої команди майже правильні, за винятком помилки, яка була допущена. Як тільки ви дізнаєтеся чому, ви ніколи цього не забудете. Погляньте на цю помилку.

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

Що це робить:

  • ^і $позначає прив’язані сірники, що стверджує, що підпалка між цими якорями - це весь збіг. Рядок буде відповідати лише у тому випадку, якщо субпатерн відповідає всій його суті, а не лише секції.
  • ()позначає групу захоплення .
  • 7|8|9означає відповідність будь-який з 7, 8або 9. Це робиться за допомогою чергувань , що і |робить оператор труби - чергуючи чергування. Це зворотний зв'язок між чергуваннями: Якщо перше чергування не збігається, двигун повинен повернутися до того, як розташування вказівника перемістилося під час матчу чергування, щоб продовжувати відповідати наступному чергуванню; Тоді як клас персонажів може просуватися послідовно. Дивіться цю відповідність у двигуні регулярного вимикання з вимкненими оптимізаціями:
Pattern: (r|f)at
Match string: carat

чергування

Pattern: [rf]at
Match string: carat

клас

  • \d{9}відповідає дев'яти цифрам. \dце скорочений метахарактер, який відповідає будь-яким цифрам.
/^[7|8|9][\d]{9}$/

Подивіться, що це робить:

  • ^і $позначає також якірні сірники.
  • [7|8|9]- клас персонажів . Будь-які символи зі списку 7, |, 8, |, або 9можуть бути підібрані, таким чином, |був доданий в неправильно. Це збігається без зворотного треку.
  • [\d]- клас символів, який населяє метахарактер \d. Поєднання використання символьного класу та одного метахарактера - це, до речі, погана ідея, оскільки шар абстракції може уповільнити збіг, але це лише деталізація реалізації та стосується лише декількох реагекс-реалізацій. JavaScript не є одним, але це робить підпаттерн трохи довшим.
  • {9} вказує, що попередній єдиний конструкт повторюється загалом дев'ять разів.

Оптимальним регулярним вираженням є те /^[789]\d{9}$/, тому що /^(7|8|9)\d{9}$/захоплює зайве, що накладає зниження продуктивності для більшості реагекс-програм (трапляється один, враховуючи, що питання використовує ключове слово varв коді, мабуть, це JavaScript). Використанняякий працює на PCRE для відповідності прег, оптимізує відсутність зворотного відстеження, однак ми також не в PHP, тому використання класів []замість чергувань |дає бонус за ефективність, оскільки збіг не відступає, і тому обидва збіги та виходять з ладу швидше, ніж використання попередній регулярний вираз.


6
просто з інтересу, від якої програми цей скриншот?
Містер Таємний гість

12

Перші 2 приклади діють дуже по-різному, якщо ви їх замінюєте чимось. Якщо ви відповідаєте цьому:

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

ви б замінили 7 або 8 або 9 порожнім рядком.

Якщо ви відповідаєте на це

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

ви будете замінити 7або 8або 9АБО ВЕРТИКАЛЬНИЙ BAR !!!! порожнім рядком.

Я щойно це з'ясував важко.


6
Ласкаво просимо до SO! Заміна або збіг - це просто неправильно. Дуже багато людей роблять цю помилку, і зазвичай вони відходять від неї - роками, іноді - тому що їхні вхідні рядки ніколи не містять трубу ( |).
Алан Мур
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.