Які спеціальні символи потрібно уникати в регулярних виразах?


389

Мені набридло завжди намагатися здогадатися, чи варто мені уникати таких спеціальних символів, як ' ()[]{}|' і т.д., коли використовую багато реалізацій регулярних виразів.

Це інакше, наприклад, з Python, sed, grep, awk, Perl, перейменувати, Apache, знайти тощо. Чи є набір правил, який підказує, коли я повинен, а коли я не повинен уникати спеціальних символів? Це залежить від типу регулярного вибору, наприклад PCRE, POSIX або розширеного регулярного виразів?


4
Хороші бібліотеки регулярних виразів мають такі функції, як " escape()" дозволяти використовувати довільні рядки як частини регулярних виразів.
ivan_pozdeev

2
Ви можете використовувати онлайн-перевіряючі засоби вираження Regex, такі як gskinner.com/RegExr (безкоштовно). (Введіть, а потім наведіть курсор миші на регулярний вираз, який ви ввели)
hexicle

2
Уникнути всіх не буквено-цифрових символів. періоду.
Салман фон Аббас

2
Це запитання було додано до поширених запитань щодо регулярного вираження стека в розділі "Інше".
aliteralmind

1
Це запитання було додано до поширених запитань про регулярне вираження стека переповнення у розділі "Послідовність втечі".
aliteralmind

Відповіді:


365

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

Для PCRE та більшості інших так званих Perl-сумісних ароматів уникайте цих класів зовнішніх символів:

.^$*+?()[{\|

і це всередині класів символів:

^-]\

Для розширених регулярних регексів POSIX (ERE) уникайте цих зовнішніх класів символів (так само, як PCRE):

.^$*+?()[{\|

Уникнення будь-яких інших символів - помилка з POSIX ERE.

Усередині класів символів зворотна косої риси є буквальним символом у регулярних виразах POSIX. Ви не можете використовувати це, щоб уникнути нічого. Ви повинні використовувати "розумне розміщення", якщо ви хочете включити метахарактеристики класів символів як літерали. Покладіть ^ де завгодно, окрім початку,] на початку, а - на початку або в кінці класу символів, щоб вони буквально відповідали цим, наприклад:

[]^-]

У базових регулярних виразах POSIX (BRE) це метахарактеристики, які вам потрібно уникнути, щоб придушити їх значення:

.^$*[\

Скорочені дужки та фігурні дужки в BRE надають їм особливого значення, яке мають їхні нерозроблені версії в ERE. Деякі реалізації (наприклад, GNU) також надають особливого значення іншим символам при виході, наприклад \? і +. Уникнення символу, відмінного від. ^ $ * () {}, Як правило, є помилкою з BRE.

Всередині класів символів BRE дотримуються того самого правила, що і ERE.

Якщо все це змушує голову крутитися, візьміть копію RegexBuddy . На вкладці Створити натисніть Вставити маркер, а потім Літерал. RegexBuddy додасть уникнути необхідності.


1
Мені здається, ви забули "/", яке також потрібно уникати поза класом.
jackthehipster

11
/не є метахарактером у жодному з ароматів регулярного вираження, про який я згадував, тому синтаксис регулярного вираження не потребує його уникнення. Коли регулярний вираз цитується як літерал на мові програмування, то рядок або регулярних виразів форматування правила цієї мови може зажадати /або "або 'бути екрановані, і може навіть вимагати `\` , щоб бути подвійно втекли.
Ян Гойваерц

2
як щодо товстої кишки, ":"? Чи слід це уникати як у класах персонажів, так і зовні? en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions говориться, що "PCRE має послідовні правила уникнення: будь-який символ, що не містить альфа-
цифри,

4
МОЖЕТЕ втекти - це не те саме, ЩО БУТЕ втекти. Синтаксис PCRE ніколи не вимагає уникнення буквальної товстої кишки, тож уникнення буквальних товстих кольорів лише робить ваш регекс важче читати.
Ян Гойвартс

1
Для не-POSIX ERE (той, який я використовую найчастіше, тому що це реалізовано Tcl), уникаючи інших речей, не створює помилок.
slebetman

61

Сучасні смаки RegEx (PCRE)

Включає C, C ++, Delphi, EditPad, Java, JavaScript, Perl, PHP (preg), PostgreSQL, PowerGREP, PowerShell, Python, REALbasic, Real Studio, Ruby, TCL, VB.Net, VBScript, wxWidgets, XML Schema, Xojo, XRegExp.
Сумісність з PCRE може відрізнятися

    У будь-якому місці: . ^ $ * + - ? ( ) [ ] { } \ |


Спадкові аромати RegEx (BRE / ERE)

Включає awk, ed, egrep, emacs, GNUlib, grep, PHP (ereg), MySQL, Oracle, R, sed.
Підтримка PCRE може бути включена в пізніших версіях або за допомогою розширень

ERE / awk / egrep / emacs

    Поза класом символів: . ^ $ * + ? ( ) [ { } \ |
    Всередині класу символів:^ - [ ]

BRE / ed / grep / sed

    Поза класом символів: . ^ $ * [ \
    Усередині класу символів: ^ - [ ]
    Для літералів не + ? ( ) { } |
    бігайте:\+ \? \( \) \{ \} \|


Примітки

  • Якщо ви не впевнені в конкретному персонажі, його можна втекти, як \xFF
  • Буквено-цифрові символи не можна уникнути за допомогою нахилу вниз
  • Довільні символи можуть бути уникнуті зворотним косою рисою в PCRE, але не BRE / ERE (уникати їх потрібно лише за потреби). Для PCRE ] -потрібно лише бігти в класах символів, але для простоти я зберігав їх у єдиному списку
  • Цитовані рядки вираження також повинні бути оточуючими лапки символів уцілілих і часто зі зворотними косими рисами в два раз вгору (наприклад , по "(\")(/)(\\.)"порівнянні /(")(\/)(\.)/з JavaScript)
  • Окрім вхідних даних, різні реабілітаційні програми можуть підтримувати різні модифікатори, класи символів, анкери, квантори та інші функції. Щоб отримати докладніші відомості, ознайомтеся з регулярними експресіями.info або використовуйте regex101.com для перевірки своїх виразів наживо

1
У вашій відповіді є багато помилок, включаючи, але не обмежуючись ними: жоден із ваших "сучасних" ароматів не вимагає -або ]не можна уникати поза класами символів. POSIX (BRE / ERE) не має символу втечі в класах символів. Аромат регексу в RTL Delphi насправді заснований на PCRE. Python, Ruby та XML мають власні аромати, ближчі до PCRE, ніж до POSIX.
Ян Гойварц

1
@JanGoyvaerts Дякуємо за виправлення Ароматизатори, які ви згадали, дійсно ближче до PCRE. Що стосується втеч, то я їх таким чином зберігав для простоти; простіше запам'ятати просто втекти скрізь, ніж кілька винятків. Користувачі живлення будуть знати, що відбувається, якщо вони хочуть уникнути декількох відхилень. У будь-якому разі я оновив свою відповідь кількома роз’ясненнями, які, сподіваюсь, стосуються деяких цих матеріалів.
Bejjor

22

На жаль, насправді не існує набору кодів втечі, оскільки він змінюється залежно від мови, якою ви користуєтесь.

Однак, зберігання такої сторінки, як сторінка « Інструменти регулярної виразності» або цього « Шаблону регулярних виразів» може пройти довгий шлях, щоб допомогти вам швидко відфільтрувати речі.


1
Чит-лист Addbytes сильно спрощений і має деякі яскраві помилки. Наприклад, він говорить \<і \>є межею слів, що є істинним лише (AFAIK) у бібліотеці підсилення регексу. Але в іншому місці воно говорить <і >є метахарактеристиками, і їх потрібно уникати (щоб \<і \>), щоб їх відповідати буквально, що не відповідає дійсності
Алан Мур,

5

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

Тож вам справді потрібно знати, який стиль ви намагаєтесь цитувати.


5

POSIX розпізнає безліч варіантів регулярних виразів - базові регулярні вирази (BRE) та розширені регулярні вирази (ERE). І навіть тоді виникають химерності через історичні реалізації утиліт, стандартизованих POSIX.

Не існує простого правила, коли слід використовувати нотації чи навіть які позначення використовує дана команда.

Ознайомтеся з книгою Джеффа Фрідла про оволодіння регулярними виразами .


4

Дійсно, немає. є близько півмільйона різних синтаксисів регулярних виразів; вони, схоже, спускаються до Perl, EMACS / GNU та AT&T взагалі, але я завжди також дивуюсь.


4

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

sed -e 's/foo\(bar/something_else/'

Я схильний просто використовувати просте визначення класу символів замість цього, так що вищевказаний вираз стає

sed -e 's/foo[(]bar/something_else/'

які я знаходжу роботи для більшості реалізацій regexp.

Класи символів BTW - це досить ванільні компоненти регулярного вирівнювання, тому вони, як правило, працюють у більшості ситуацій, коли вам потрібно уникнути символів у регулярних виразах.

Редагувати: Після коментаря нижче, я просто подумав про те, що ви також повинні враховувати різницю між автоматами кінцевого стану та автоматами без кінцевих станів, дивлячись на оцінку поведінки повторного виведення.

Ви можете поглянути на "блискучу книгу балів" aka Effective Perl ( санітоване посилання Amazon ), зокрема, розділ про регулярні вирази, щоб отримати відчуття різниці в типах оцінювання двигуна regexp.

Не у всьому світі PCRE!

У будь-якому випадку, regexp настільки незграбні порівняно з SNOBOL ! Тепер це був цікавий курс програмування! Поряд із тим на Симулі .

Ах радості від навчання в УНСЗ наприкінці 70-х! (-:


'sed' - це команда, для якої звичайна '(' не є спеціальною, але '\ (' є спеціальною; на відміну від PCRE повертає сенс, так '(' є спеціальним, але '\ (' не є. Це саме те, що ОП просить про те
Джонатан Леффлер

sed - це утиліта * nix, яка використовує один із найпримітивніших наборів оцінювання регулярних виразів. PCRE не входить у ситуацію, яку я описую, оскільки вона включає інший клас (не) кінцевих автоматів з тим, як він оцінює регулярні вирази. Я думаю, що моя пропозиція щодо мінімального набору синтаксису regexp все ще є.
Роб Уеллс

1
У сумісній з POSIX системі sed використовує POSIX BRE, про що я висвітлюю свою відповідь. Версія GNU в сучасній системі Linux використовує POSIX BRE з кількома розширеннями.
Ян Гойвартс

2

Для PHP "завжди безпечно передувати не алфавітно-цифровому знаку з" \ ", щоб вказати, що він стоїть за собою". - http://php.net/manual/en/regexp.reference.escape.php .

За винятком випадків, коли це "або".: /

Щоб уникнути змінних шаблонів регулярних виразів (або часткових змінних) у PHP, використовуйте preg_quote ()


2

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

Будьте в курсі, як обробляється рядок у пам'яті: якщо може бути звичайна рядок всередині коду або рядок, що вводиться в командний рядок, але a може бути або інтерактивним командним рядком, або командним рядком, зазначеним всередині файлу сценарію оболонки, або всередині змінної в пам'яті, згаданої кодом, або (рядкового) аргументу шляхом подальшої оцінки, або рядка, що містить код, що генерується динамічно з будь-яким видом інкапсуляції ...

Кожному з цього контексту призначені деякі символи з особливою функціональністю.

Коли ви хочете передати персонаж буквально, не використовуючи його спеціальної функції (локальної для контексту), тоді вам слід уникнути цього, для наступного контексту ... який може потребувати інших символів втечі, які, можливо, додатково повинні бути вийшли з попереднього контексту. Крім того, можуть бути такі речі, як кодування символів (найбільш підступним є utf-8, тому що він схожий на ASCII для загальних символів, але може бути необов'язково інтерпретований навіть терміналом залежно від його налаштувань, щоб він міг поводитися по-різному, то атрибут кодування HTML / XML, потрібно правильно зрозуміти процес.

Наприклад, регулярний вираз в командному рядку, починаючи з perl -npe, потрібно перенести до набору системних викликів exec, що з'єднує в якості труби файл файлів, кожен із цих викликів системи exec просто містить список аргументів, які були розділені між (пропущеними) пробілами, і, можливо, труби (|) та перенаправлення (> N> N> & M), дужки, інтерактивне розширення *та ?,$(())... (все це - спеціальні символи, які використовуються * sh, які можуть здатися перешкоджати символу регулярного виразу в наступному контексті, але вони оцінюються в порядку: перед командним рядком. Командний рядок читається програма як bash / sh / csh / tcsh / zsh, по суті всередині подвійної або однієї цитати, втеча простіша, але не потрібно цитувати рядок у командному рядку, оскільки в основному простір має бути попередньо встановлений зворотною косою рисою, і цитата є не потрібно залишати доступним функціонал розширення для символів * і?, але цей синтаксичний розбір настільки ж інший контекст, як у цитаті. Потім, коли оцінюється командний рядок, отриманий в пам'яті регулярний вираз (не такий, як написано в командному рядку) отримує те саме обробку, що і його буде у вихідному файлі. Для regexp є контекст набору символів у квадратних дужках [],регулярний вираз perl може бути процитований великим набором символів, що не містять літер (наприклад, m // або m: / краще / для / шлях: ...).

У вас є більше деталей про символи в іншій відповіді, які дуже специфічні для остаточного контексту регулярного виразка. Як я зазначив, ви згадуєте, що ви знаходите втечу з регулярних викидів із спробами, ймовірно, тому, що різний контекст має різний набір символів, який плутає вашу пам’ять про спроби (часто зворотний косий знак - це символ, який використовується в тому іншому контексті, щоб уникнути буквального символу замість його функції ).



0

Для Ionic (Typescript) вам потрібно подвоїти косу рису, щоб відбити зображення. Наприклад (це відповідність деяким спеціальним символам):

"^(?=.*[\\]\\[!¡\'=ªº\\-\\_ç@#$%^&*(),;\\.?\":{}|<>\+\\/])"

Зверніть увагу на цих ] [ - _ . /персонажів. Вони повинні бути подвійними. Якщо цього не зробити, у вас буде помилка типу.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.