Регулярні вирази, основи для роботи в Linux

  1. 1. Традиційні регулярні вирази (вони ж основні, базові та basic regular expressions (BRE))
  2. перерахування |
  3. Угруповання або об'єднання ()
  4. Квантификация {}? * +
  5. жадібність regex

Доброго часу, гості!

У сьогоднішній статті хочу торкнутися такої величезної теми як Регулярні вирази. Думаю всім відомо, що тема регексов (так регулярні вирази називаються на сленгу) - неосяжна в обсязі одного поста. Тому постараюся коротко, але як можна зрозуміліше зібрати в купу свої думки і донести їх до Вас в своєму блозі .

Почну з того, що існує кілька різновидів регулярних виразів:

1. Традиційні регулярні вирази (вони ж основні, базові та basic regular expressions (BRE))

  • синтаксис даних виразів визначено, як застарілий, але тим не менше до сих пір широко поширений і використовується багатьма утилітами UNIX
  • Основні регулярні вирази включають в себе наступні метасимволи (про їх значеннях нижче):
    • .
    • []
    • [^]
    • ^
    • $
    • *
    • \ {\} - початковий варіант для {} (в розширених)
    • \ (\) - початковий варіант для () (в розширених)
    • \ N, де n - номер від 1 до 9
  • Особливості використання даних метасимволов:
    • Зірочка повинна слідувати після висловлення, відповідного одиничного символу. Приклад: [xyz] *.
    • Вираз \ (блок \) * слід вважати неправильним. У деяких випадках воно відповідає нулю або більше повторень рядки блок. В інших воно відповідає рядку блок *.
    • Усередині символьного класу спеціальні значення символів, в основному, ігноруються. Особливі випадки:
    • Щоб додати символ ^ в набір, його слід помістити туди не першим.
    • Щоб додати символ -в набір, його слід помістити туди першим або останнім. наприклад:
      • шаблон DNS-імені, куди можуть входити літери, цифри, мінус і точка-роздільник: [-0-9a-zA-Z.];
      • будь-який символ, крім мінуса і цифри: [^ -0-9].
    • Щоб додати символ [або] в набір, його слід помістити туди першим. наприклад:
      • [] [Ab] відповідає], [, a або b.

2. Розширені регулярні вирази (вони ж extended regular expressions (ERE))

  • Синтаксис даних виразів аналогічний синтаксису основних виразів, за винятком:
    • Скасовано використання зворотної косої межі для метасимволов {} і ().
    • Зворотна коса риска перед метасимволом скасовує його спеціальне значення.
    • Відкинута теоретично нерегулярна конструкція \ n.
    • Додані метасимволу +,?, |.

3. Регулярні вирази, сумісні з Perl (вони ж Perl-compatible regular expressions (PCRE))

  • мають більш багатий і в той же час передбачуваний синтаксис, ніж навіть POSIX ERE, тому часто використовується додатками.

Далі трохи поговоримо про синтаксис регулярних виразів.

Регулярні вирази складаються з шаблонів, вірніше сказати задають шаблон пошуку. Шаблон складається з правил пошуку, які складаються з символів і метасимволов.

Правила пошуку визначаються наступними операціями:

перерахування |

Вертикальна риса (|) розділяє допустимі варіанти, можна сказати - логічне АБО. Наприклад, «gray | grey» відповідає gray або grey.

Угруповання або об'єднання ()

Круглі дужки використовуються для визначення області дії і пріоритету операторів. Наприклад, «gray | grey» і «gr (a | e) y» є різними зразками, але вони обидва описують безліч, що містить gray і grey.

Квантификация {}? * +

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

{m, n}

загальне вираз, повторень може бути від m до n включно.

{m}

загальне вираз, m і більш повторень.

{, n}

загальне вираз, не більше n повторень.

{n}

рівно n повторень.

?

Знак питання означає 0 або 1 раз, то ж саме, що і {0,1}. Наприклад, «colou? R» відповідає і color, і colour.

*

Зірочка означає 0, 1 або будь-яке число раз ({0,}). Наприклад, «go * gle» відповідає ggle, gogle, google та ін.

+

Плюс означає хоча б 1 раз ({1,}). Наприклад, «go + gle» відповідає gogle, google і т. Д. (Але не ggle).

Конкретний синтаксис даних регулярних виразів залежить від реалізації. (тобто в базових регулярних виразах символи {і} - екрануються зворотним слешем)

Метасимволи, кажучи простою мовою - це символи, які не відповідають своїм реальним значенням, тобто символ. (Точка) - це не крапка, а будь-який один символ, і т.п. прошу ознайомитися з метасимвол і їх значеннями:

. відповідає одному будь-якому символу [щось] Відповідає будь-якому одиничному символу з числа ув'язнених в дужки. При цьому: Символ «-» інтерпретується буквально тільки в тому випадку, якщо він розташований безпосередньо після відкриває або перед закриваючою дужкою: [abc-] або [-abc]. В іншому випадку, він позначає інтервал сімволов.Напрімер, [abc] відповідає «a», «b» або «c». [Az] відповідає буквах нижнього регістра латинського алфавіту. Ці позначення можуть і поєднуватися: [abcq-z] відповідає a, b, c, q, r, s, t, u, v, w, x, y, z.Чтоби встановити відповідність символам «[» або «]», досить, щоб закриває дужка була першим символом після відкриває: [] [ab] відповідає «]», «[», «a» або «b» .Якщо значення в квадратних скобах предварило символом ^, то значення виразу відповідає одиничного символу з числа тих, яких немає в дужках. Наприклад, [^ abc] відповідає будь-якому символу, крім «a», «b» або «c». [^ Az] відповідає будь-якому символу, крім символів нижнього регістру в латинському алфавіті. ^ Відповідає початку тексту (або початку будь-якого рядка, якщо режим порядковий). $ Відповідає кінця тексту (або кінця будь-якого рядка, якщо режим порядковий). \ (\) Або () Оголошує «зазначене підвираз» (згруповане вираз), яке може бути використано пізніше (див. Наступний елемент: \ n). «Зазначене підвираз» також є «блоком». На відміну від інших операторів, цей (в традиційному синтаксисі) вимагає бекслеша, в розширеному і Perl символ \ - не потрібен. \ N Де n - це цифра від 1 до 9; відповідає n -му зазначеного подвираженія (наприклад (abcd) \ 0, тобто символи abcd відзначені нулем). Ця конструкція теоретично нерегулярна, вона не була прийнята в розширеному синтаксисі регулярних виразів. *
  • Зірочка після висловлення, відповідного одиничного символу, відповідає нулю або більше копій цього (попереднього) вираження. Наприклад, «[xyz] *» відповідає порожній рядку, «x», «y», «zx», «zyx», і т. Д.
  • \ N *, де n - це цифра від 1 до 9, відповідає нулю або більше входжень для відповідності n -го зазначеного подвираженія. Наприклад, «\ (a. \) C \ 1 *» відповідає «abcab» і «abcaba», але не «abcac».

!!! Вираз, укладену в «\ (» і «\)» і супроводжуване «*», слід вважати неправильним. У деяких випадках, воно відповідає нулю або більше входжень рядка, яка була укладена в дужки. В інших, воно відповідає висловом, укладеним в дужки, враховуючи символ «*».

\ {X, y \} Відповідає останньому (майбутнього) блоку, що зустрічається не менше x і не більше y раз. Наприклад, «a \ {3,5 \}» відповідає «aaa», «aaaa» або «aaaaa». На відміну від інших операторів, цей (в традиційному синтаксисі) вимагає бекслеша. . * Позначення будь-якої кількості будь-яких символів між двома частинами регулярного виразу.

Метасимволи нам допомагають використовувати різні відповідності. Але як же представити метасимвол звичайним символом, тобто символ [(квадратна дужка) значенням квадратної дужки? просто:

  • необхідно попередити (екранувати) метасимвол (. * + \? [] {}) зворотним слешем. Наприклад \. або \ [

Для спрощення завдання деяких наборів символів, їх об'єднали в т.зв. класи і категорії символів. POSIX стандартизованих оголошення деяких класів і категорій символів, як показано в таблиці нижче:

POSIX клас аналогічно позначення [: upper:] [AZ] символи верхнього регістру [: lower:] [az] символи нижнього регістра [: alpha:] [A-Za-z] символи верхнього і нижнього регістра [: alnum:] [A -Za-z0-9] цифри, символи верхнього і нижнього регістра [: digit:] [0-9] цифри [: xdigit:] [0-9A-Fa-f] шістнадцятиричні цифри [: punct:] [.,! ?: ...] знаки пунктуації [: blank:] [\ t] пробіл і TAB [: space:] [\ t \ n \ r \ f \ v] символи пропуску [: cntrl:] символи управління [: graph:] [ ^ \ t \ n \ r \ f \ v] символи друку [: print:] [^ \ t \ n \ r \ f \ v] символи друку і символи пропуску

У regex є таке поняття як:

жадібність regex

Постараюся описати як можна зрозуміліше. Припустимо, ми хочемо знайти всі HTML теги в якомусь тексті. Локалізувавши завдання, ми хочемо знайти значення укладені між <і>, разом з цими самими дужками. Але ми знаємо, що теги мають різну довжину і самих тегів, як мінімум штук 50. Перераховувати їх все, уклавши в метасимволу [] - завдання надто трудомістка. Але ми знаємо, що у нас є вираз. * (Точка зірочка), що характеризує будь-яке число будь-яких символів в рядку. За допомогою цього виразу ми спробуємо знайти в тексті (<p> Отже, <strong> Як створити RAID рівня 10/50 на контролері LSI MegaRAID (актуально і для: Intel SRCU42x, Intel SRCS16): </ strong> <span id = " more-2058 "> </ span> </ p>) все значення між <і>. В результаті, цього виразу буде відповідати ВСЯ рядок. чому, тому що регекс - жадібний і намагається захопити БУДЬ ВСЕ кількість символів між <і>, відповідно вся рядок, починаючи <p> Отже, ... і закінчуючи ... </ span> </ p> буде належати даному правилу!

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

  • врахувати символи, які не відповідають бажаному зразком (наприклад: <[^>] *> для вищеописаного випадку)
  • позбавити від жадібності, додавши визначенні квантіфікатора, як нежадібні:
    • *? - «не жадібний» ( «ледачий») еквівалент *
    • +? - «не жадібний» ( «ледачий») еквівалент +
    • {N,}? - «не жадібний» ( «ледачий») еквівалент {n,}
    • . *? - «не жадібний» ( «ледачий») еквівалент. *

Все вищенаписане хочу доповнити синтаксисом розширених регулярних виразів:

Регулярні вирази в POSIX аналогічні традиційному Unix-синтаксису, але з додаванням деяких метасимволов:

+

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

?

Знак питання робить попередній символ або групу необов'язковою. Іншими словами, у відповідному рядку вона може бути відсутнім, або бути присутнім рівно один раз.

|

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

Також було скасовано використання зворотної косої межі: \ {... \} стає {...} і \ (... \) стає (...).

На завершення посту, наведу деякі приклади використання regex:

[Regex @ regexp k-max.name] $ cat text1 1 apple 2 pear 3 banana [regex @ regexp k-max.name] $ grep p text1 1 apple 2 pear [regex @ regexp k-max.name] $ grep pea text1 2 pear [regex @ regexp k-max.name] $ grep "p *" text1 1 apple 2 pear 3 banana [regex @ regexp k-max.name] $ grep "pp *" text1 1 apple 2 pear [regex @ regexp k-max.name] $ grep "x" text1 [regex @ regexp k-max.name] $ grep "x *" text1 1 apple 2 pear 3 banana [regex @ regexp k-max.name] $ cat text1 | grep "l \ | n" 1 apple 3 banana [regex @ regexp k-max.name] $ echo -e "find an \ n * here" | grep "\ *" * here [regex @ regexp k-max.name] $ grep "pp \ +" text1 # рядки, з вмістом однієї р і 1 і більше р 1 apple [regex @ regexp k-max.name] $ grep "pl \? e" text1 1 apple 2 pear [regex @ regexp k-max.name] $ grep "pl \? e" text1 # pe з можливим символом l 1 apple 2 pear [regex @ regexp k-max.name ] $ grep "p. * r" text1 # p, в рядках де є r 2 pear [regex @ regexp k-max.name] $ grep "a .." text1 # рядки з a, за якою слідує як мінімум 2 символи 1 apple 3 banana [regex @ regexp k-max.name] $ grep "\ (an \) \ +" text1 # Пошук більш повторення an 3 banana [regex @ regexp k-max.name] $ grep "an \ (an \) \ + "text1 # пошук 2х повторень an 3 banana [regex @ regexp k-max.name] $ grep" [3p] "text1 # пошук рядків, де є 3 або p 1 apple 2 pear 3 banana [regex @ regexp k-max.name] $ echo -e "find an \ n * here \ nsomewhere." | grep "[. *]" * here somewhere. [Regex @ regexp k-max.name] $ # Шукає символи від 3 до 7 [regex @ regexp k-max.name] $ echo -e "123 \ n456 \ n789 \ n0" | grep "[3-7]" 123 456 789 [regex @ regexp k-max.name] $ # Шукаємо цифру, за якою до кінця рядка немає букв n і r [regex @ regexp k-max.name] $ grep "[ [: digit:]] [^ nr] * $ "text1 1 apple [regex @ regexp k-max.name] $ sed -e '/ \ (a. * a \) \ | \ (p. * p \) / s / a / A / g 'text1 # заміна а на а у всіх рядках, де після а йде а чи після р йде р 1 Apple 2 pear 3 bAnAnA [regex @ regexp k-max.name] $ sed -e' / ^ [^ lmnXYZ] * $ / s / ear / each / g 'text1 # заміна ear на each в рядках не починати на lmnXYZ 1 apple 2 peach 3 banana [regex @ regexp k-max.name] $ echo "First. A phrase. This is a sentence. " | \ # Заміна останнього слова в реченні на LAST WORLD. & Amp; amp; gt; sed -e 's / [^] * \ ./ LAST WORD./g' First. A LAST WORD. This is a LAST WORD.

З повагою, Mc.Sim!

Інші матеріали в категорії Linux

Додані метасимволу +,?
Квантификация {}?
Наприклад, «colou?
Але як же представити метасимвол звичайним символом, тобто символ [(квадратна дужка) значенням квадратної дужки?
Name] $ grep "pl \?
Name] $ grep "pl \?