Чому моє регулярне вираження працює в X, а не в Y?


76

Я написав регулярний вираз, який добре працює в певній програмі (grep, sed, awk, perl, python, ruby, ksh, bash, zsh, find, emacs, vi, vim, gedit,…). Але коли я використовую його в іншій програмі (або в іншому варіанті unix), вона припиняє збігатися. Чому?

Відповіді:


102

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

Наслідком цього є те, що якщо у вас є регулярний вираз, який працює в одному інструменті, вам може знадобитися модифікувати його для роботи в іншому інструменті. Основні відмінності між поширеними інструментами:

  • чи потрібні оператори +?|(){}зворотної косої риски;
  • які розширення підтримуються за межами основ .[]*^$і зазвичай+?|()

У цій відповіді я перелічу основні стандарти . Перевірте документацію інструментів, якими ви користуєтесь, щоб отримати детальну інформацію.

Порівняння Вікіпедії двигунів регулярної експресії містить таблицю з переліком функцій, підтримуваних загальними реалізаціями.

Основні регулярні вирази (BRE)

Основні регулярні вирази кодифіковані стандартом POSIX . Це синтаксис, що використовується grep, sedі vi. Цей синтаксис містить такі функції:

  • ^і $збігаються лише на початку та в кінці рядка.
  • . відповідає будь-якому символу (або будь-якому символу, крім нового рядка).
  • […]відповідає будь-якому одному символу, вказаному всередині дужок (набір символів). Якщо першим символом після вступної дужки є а ^, символи, які не перераховані, замість цього відповідають. Щоб включити a ], поставте його відразу після відкриття [(або після, [^якщо це негативний набір). Якщо -між двома символами, він позначає діапазон; щоб включити буквальний -, покладіть його там, де його неможливо проаналізувати як діапазон.
  • Зворотна коса перед будь-яким ^$.*\[цитуванням наступного символу.
  • * відповідає попередньому символу або під вираженню 0, 1 або більше разів.
  • \(…\)є синтаксичною групою для використання з *оператором або зворотними посиланнями та \DIGITзамінами.
  • Зворотні \1, \2... відповідає точний текст , що співпадає по відповідній групі, наприклад , \(fo*\)\(ba*\)\1матчі , foobaafooале не foobaafo. Не існує стандартного способу посилання на 10-ту групу і далі (стандартним значенням \10є перша група, а за нею - a 0).

Наступні функції також є стандартними, але відсутні у деяких обмежених реалізаціях:

  • \{m,n\}відповідає попередньому символу або підвиразку від m до n разів; n або m може бути опущено, і означає рівно m .\{m\}
  • Всередині дужок можуть використовуватися класи символів , наприклад, [[:alpha:]]відповідність будь-якій букві. Сучасні реалізації дужок виразів ) також включають елементи, що складаються, як [.ll.]і класи еквівалентності, як [=a=].

Нижче наведені поширені розширення (особливо в інструментах GNU), але вони зустрічаються не у всіх реалізаціях. Перевірте посібник із використовуваного інструменту.

  • \|для чергування: foo\|barсірники fooабо bar.
  • \?(short for \{0,1\}) та \+(short for \{1,\}) збігаються з попереднім символом або субекспресією максимум 1 раз або принаймні 1 раз відповідно.
  • \nвідповідає новому рядку, \tвідповідає вкладці тощо.
  • \wвідповідає будь-якій складовій слова (короткий, [_[:alnum:]]але з варіацією, якщо мова йде про локалізацію) і \Wвідповідає будь-якому символу, який не є складовим словом.
  • \<і \>відповідати порожній рядку лише на початку або в кінці слова відповідно; \bчи то, чи ні, чи \Bтам, де \bнемає.

Зауважте, що інструменти без \|оператора не мають повної потужності регулярних виразів. Зворотні параметри дозволяють зробити кілька додаткових речей, які неможливо зробити за допомогою регулярних виразів у математичному сенсі.

Розширені регулярні вирази (ERE)

Розширені регулярні вирази кодифіковані стандартом POSIX . Їх головна перевага перед BRE - регулярність: всі стандартні оператори - це голі пунктуаційні символи; зворотний косий ривок перед пунктуаційним символом завжди цитує його. Це синтаксис , який використовується awk, grep -Eабо egrep, GNU sed -r, і Bash=~ - оператор. Цей синтаксис містить такі функції:

  • ^і $збігаються лише на початку та в кінці рядка.
  • . відповідає будь-якому символу (або будь-якому символу, крім нового рядка).
  • […]відповідає будь-якому одному символу, вказаному всередині дужок (набір символів). Доповнення початковим ^і діапазоном працює, як у BRE (див. Вище). Класи символів можна використовувати, але вони відсутні у кількох реалізаціях. Сучасні реалізації також підтримують класи еквівалентності та елементи співставлення. Зворотна косої риски у дужках цитує наступний символ у деяких, але не у всіх реалізаціях; використовувати \\для позначення зворотної косої риски для переносимості.
  • (…)є синтаксичною групою, для використання *або \DIGITзаміни.
  • |для чергування: foo|barсірники fooабо bar.
  • *, +і ?кілька разів відповідає попередньому символу чи підвираженню: 0 або більше для *, 1 або більше для +, 0 або 1 для ?.
  • На зворотному косі цитується наступний символ, якщо він не буквено-цифровий.
  • {m,n}відповідає попередньому символу або підвираженню між m і n разів (відсутнє в деяких реалізаціях); n або m може бути опущено, і означає рівно m .{m}
  • Деякі поширені розширення, як у BRE: backreferences (помітно відсутні в awk, за винятком реалізації реалізованої зайнятості, де ви можете використовувати ); спеціальні символи , і т.д.; межі слів і , складові слова та ,…\DIGIT$0 ~ "(...)\\1"\n\t\b\B\b\B

PCRE (Perl-сумісні регулярні вирази)

PCRE - це розширення ERE, спочатку запроваджені Perl та прийняті GNU grep -Pта багатьма сучасними інструментами та мовами програмування , як правило, через бібліотеку PCRE . Дивіться документацію Perl для приємного форматування з прикладами. Не всі функції останньої версії Perl підтримуються PCRE (наприклад, виконання коду Perl підтримується лише в Perl). Дивіться посібник PCRE, щоб отримати підсумок підтримуваних функцій. Основні доповнення до ERE:

  • (?:…)це група (…), яка не захоплює: подобається , але не враховує зворотних посилань.
  • (?=FOO)BAR(lookahead) відповідає BAR, але лише за наявності матчу для FOOстарту з тієї ж позиції. Це найкорисніше, щоб прив’язати матч, не включаючи до нього наступний текст: foo(?=bar)матчі, fooале лише за ним bar.
  • (?!FOO)BAR(негативний lookahead) збігається BAR, але FOOна цій же позиції також немає відповідності. Наприклад, (?!foo)[a-z]+відповідає будь-якому малому слову, яке не починається з foo; [a-z]+(?![0-9)відповідає будь-якому малому слову, за яким не йде цифра (так foo123, він відповідає, foале ні foo).
  • (?<=FOO)BAR(дивлячись позаду) матчі BAR, але лише якщо йому одразу передує матч за FOO. FOOповинна мати відому довжину (не можна використовувати такі оператори повторення, як *). Це найкорисніше прив’язувати відповідність, не включаючи попередній текст у відповідність: (?<=^| )fooзбіги, fooале лише якщо йому передує пробіл або початок рядка.
  • (?<!FOO)BAR(Негативний перегляду назад) збігається BAR, але тільки якщо це не безпосередньо перед матчем за FOO. FOOповинна мати відому довжину (не можна використовувати такі оператори повторення, як *). Це найкорисніше прив’язати відповідність, не включаючи попередній текст у відповідність: (?<![a-z])fooзбіги, fooале лише якщо перед цим не передує мала літера.

Emacs

Синтаксис Emacs є проміжним між BRE та ERE. Окрім Emacs, це синтаксис за замовчуванням -regexу пошуку GNU. Emacs пропонує наступних операторів:

  • ^, $, ., […], *, +, ?Як і в ERE
  • \(…\), \|, \{…\}, Як і в BRE\DIGIT
  • більше послідовностей зворотних літер ; \<і \>для меж слова; та багато іншого в останніх версіях Emacs, які часто не підтримуються в інших двигунах із синтаксисом, подібним до Emacs.

Шкаралупа кульок

Шар оболонок (макіяжів) виконує відповідність візерунків із синтаксисом, який повністю відрізняється від регулярних виразів і менш потужним. Окрім оболонок, ці символи доступні з іншими інструментами, такими як find -nameі фільтри rsync. Шаблони POSIX містять такі функції:

  • ? відповідає будь-якому одному символу.
  • […]це набір символів, як у звичайних синтаксисах регулярних виразів. Деякі оболонки не підтримують класів символів. Деякі снаряди вимагають !замість того, ^щоб зняти набір.
  • *відповідає будь-якій послідовності символів (часто, за винятком випадків, /коли збігаються шляхи до файлів; якщо /вони виключені *, то **іноді включають /, але перевіряють документацію інструмента).
  • На зворотному косі цитується наступний символ.

Ksh пропонує додаткові функції, які надають його шаблону, що відповідає всій силі регулярних виразів. Ці функції також доступні в bash після запуску shopt -s extglob. Zsh має інший синтаксис, але також може підтримувати синтаксис ksh після setopt ksh_glob.


Інші багаті НП, які ви можете згадати, - це vim"s" та "AT&T libast" (як у ksh93).
Стефан Шазелас

@ StéphaneChazelas Окрім програми vim, яка програма використовує vim regexps? Крім ksh, яка програма використовує libast?
Жиль

все набір інструментів AT & T використовує AT & T (УЕ grep, tw, expr...). За винятком kshцього набору інструментів рідко можна зустріти поза межами AT&T.
Стефан Шазелас

Згідно з моїм розумінням (та з Вікіпедії), ваш термін "Клас символів" насправді відноситься до "класу символів POSIX" ... однак, він regex(7)погоджується з вами і називає [these]"дужки вирази" та (в межах "дужки вирази") [:these:]"класи символів". Я не впевнений, як найкраще це вирішити.
Адам Кац

Як би ви їх не називали, вони підтримують діапазони. Безумовно, варто відзначити, що -вказується дальність і слід або уникати, спочатку (після необов'язкового ^), або останнього, якщо його слід сприймати буквально. (Я бачив багато помилок , обумовлених , наприклад , [A-z]-ПРІМЕЧАНІЕ зміни в прецедентної, який відповідає символи кодів 65 до 122 і випадково включає в себе кожен з: [\]^_`. Я також бачив , дійсний ще заплутаним , [!-~]щоб відповідати все друковані символи в ANSI , яку я вважаю за краще [\x21-\x7e], що є принаймні прямолінійною у своїй дії, хоча і заплутаною в іншому вимірі.)
Адам Кац
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.