JavaRush/Java блог/Random UA/RegEx: 20 коротких кроків для освоєння регулярних виразів...
Artur
40 рівень

RegEx: 20 коротких кроків для освоєння регулярних виразів. Частина 1

Стаття з групи Random UA
учасників
Оригінал цієї статті тут . Напевно, теорії багато не буває, і я наведу кілька посилань на докладніший матеріал щодо regex наприкінці статті. Але мені здалося, що починати вникати в таку тему як регулярні висловлювання буде набагато цікавіше, якщо є можливість займатися не тільки зубрінням, а й одразу закріплювати знання, виконуючи невеликі завдання під час навчання. RegEx: 20 коротких кроків для освоєння регулярних виразів.  Частина 1 - 1Мабуть, приступимо. Зазвичай противники використання регулярних виразів ('RegEx' або просто 'regex') у програмуванні наводять наступну цитату, що приписується Джеймі Завінські: " Деякі люди, стикаючись із проблемою, думають: "Я знаю, я використовуватиму регулярні висловлювання". Тепер у них дві проблеми”. Насправді використання регулярних виразів ще не є хорошою або поганою ідеєю. І це саме по собі не додасть проблем і не вирішить жодної з них. Це всього лише інструмент. І те, як ви його використовуєте (правильно чи неправильно), визначає, які результати ви побачите. Якщо ви спробуєте використовувати regex, наприклад, для створення HTML-парсера, то ви, швидше за все, зазнаєте болю. Але якщо ви хочете просто витягти, наприклад, тимчасові мітки з деяких рядків, у вас, ймовірно, буде все гаразд. Щоб полегшити освоєння регулярних виразів, я зібрав цей урок, який допоможе вам з нуля опанувати регулярні вирази всього за двадцять коротких кроків. Це керівництво здебільшого фокусується на основних поняттях регулярних виразів і заглиблюється у складніші теми лише за необхідності.

Крок 1: для чого потрібно використовувати регулярні вирази

RegEx: 20 коротких кроків для освоєння регулярних виразів.  Частина 1 - 2Регулярні вирази використовуються для пошуку збігів у тексті за заданими шаблонами (зразками). За допомогою regex ми можемо легко і просто витягувати ізюм із кексу слова з тексту, а також окремі літеральні (літеральні) та мета (спеціальні) символи та їх послідовності, що відповідають певним критеріям. Ось що говорить нам про них Вікіпедія: Регулярні вирази (англ. regular expressions) - формальна мова пошуку та здійснення маніпуляцій з підрядками в тексті, заснований на використанні метасимволів (символів-джокерів, англ. Wildcard characters). Для пошуку використовується рядок-зразок (англ. pattern, російською його часто називають "шаблоном", "маскою"), що складається з символів і метасимволів і задає правило пошуку. Для маніпуляцій з текстом додатково задається рядок заміни, який також може містити спеціальні символи. Шаблон може бути таким же простим, як, наприклад, слово dogв цій пропозиції:
Quick brown fox jumps over lazy dog.
Цей регулярний вираз виглядає так:
dog
... Досить легко, чи не так? Зразком може бути будь-яке слово, що містить букву o. Регулярний вираз для пошуку такого шаблону може виглядати так:
\w * o\w *
( Випробувати цей регулярний вираз можна тут), можна зауважити, що в міру ускладнення вимог до "відповідності", регулярне вираження також ускладнюється. Існують додаткові форми запису для вказівки груп символів і відповідності шаблонів, що повторюються, що я поясню нижче. Але як тільки ми знаходимо відповідність шаблону в якомусь тексті, то що ж ми можемо з ним робити? Сучасні движки регулярних виразів дозволяють витягувати символи або їх послідовності (підрядки) з тексту, або видаляти їх, або замінювати їх іншим текстом. Загалом, регулярні висловлювання використовуються для аналізу та маніпулювання текстом. Ми можемо витягти, наприклад, підрядки, які виглядають як IP-адресаи, а потім спробувати перевірити їх. Або ми можемо отримати імена та адресаи електронної пошти та зберегти їх у базі даних. Або використовувати регулярні вирази, щоб знайти конфіденційну інформацію (наприклад, номери паспортів або номери телефонів) в електронних листах і попередити користувача про те, що він може бути ризикованим. Regex справді універсальний інструмент, який легко вивчити, але важко освоїти: "Так само, як є різниця між хорошим виконанням музичного твору та створенням музики, є і різниця між знанням регулярних висловів та їх розумінням". - Джеффрі Е. Ф. Фрідл, Освоєння регулярних виразів

Крок 2: квадратні дужки[]

Найпростіші регулярні вирази, які легко зрозуміти - це ті, які лише шукають відповідність по-символьно між шаблоном регулярного виразу і цільовим рядком. Давайте, наприклад, спробуємо знайти кота: RegEx: 20 коротких кроків для освоєння регулярних виразів.  Частина 1 - 3
pattern: cat
.
matches:      ^^^
( Як це працює у справі - дивіться тут ) NB! Усі рішення представлені тут лише як варіанти рішень. У регулярних висловлюваннях, як й у програмуванні взагалі, можна вирішувати одні й самі завдання різними способами. Однак, крім суворого по-символьного порівняння, ми також можемо вказати альтернативні збіги, використовуючи квадратні дужки:
pattern: ca[rt]
.
matches:      ^^^ ^^^
( Як це працює ) Відкриваючі та закриваючі квадратні дужки повідомляють механізму регулярних виразів, що він повинен шукати будь-який із зазначених символів, але тільки один. Вищезгадане регулярне вираження не знайде, наприклад, слово cartцілком, а знайде тільки його частину:
pattern: ca[rt]
string: кіт був вирізати, коли він ходить під карту.
matches:      ^^^ ^^^
( Як це працює ) Коли ви використовуєте квадратні дужки, ви вказуєте механізму регулярних виразів, щоб він шукав збігу лише з одним із символів, що містяться у дужках. Двигун знаходить символ c, потім символ a, але якщо наступний символ не rабо t, це ще повний збіг. Якщо він знаходить ca, а потім або , rабо tвін зупиняється. Він не намагатиметься зіставити більше символів, тому що квадратні дужки вказують, що потрібно шукати лише один із символів, що містяться. Коли він знаходить ca, то наступним знаходить rу слові cart, і зупиняється, тому що він вже знайшов збіг послідовності car.

Завдання для тренування:

Напишіть регулярний вираз, який знаходить усі 10 збігів із шаблонами hadі Hadв цьому уривку неперекладної гри слів на місцевому діалекті:
pattern:
string: Jim, де Bill had had "had" , had had "had had" . "Had had" had been correct.
matches:                  ^^^ ^^^ ^^^ ^^^ ^^^ ^^^ ^^^ ^^^ ^^^ ^^^
( Дивіться можливе рішення тут ) А як щодо всіх назв тварин у наступному реченні?
pattern:
string: Bat, cat, and rat walked in bar...
matches:    ^^^ ^^^ ^^^
( Можливе рішення ) Або ще простіше: знайдіть слова barабо bat:
pattern:
string: Bat, cat, and rat walked in bar...
matches:    ^^^ ^^^
( Можливе рішення ) Ось ми вже й навчабося писати більш-менш складні регулярні висловлювання, і ми лише на кроці 2! Продовжуємо!

Крок 3: escape-послідовності

RegEx: 20 коротких кроків для освоєння регулярних виразів.  Частина 1 - 4На попередньому етапі ми дізналися про квадратні дужки []і про те, як вони допомагають нам знайти альтернативні збіги за допомогою движка regex. А якщо ми хочемо знайти збіги у вигляді самих відкритих і закритих квадратних дужок []? Коли ми хотіли знайти по-символьне збіг зі словом cat, ми надавали движку regex цю послідовність символів ( cat). Давайте спробуємо знайти квадратні дужки []таким же способом:
pattern: [] 
string: Ви не можете match [] using regex! You will regret this!
matches: 
( Дивимося що вийшло ) Щось не спрацювало, однак... Це відбувається тому, що символи квадратної дужки працюють як спеціальні символи движка regex, які зазвичай використовуються для позначення чогось іншого, і не є буквальним шаблоном для пошуку їх самих. Як ми пам'ятаємо з кроку 2, вони використовуються для пошуку альтернативних збігів, щоб двигун regex міг знайти відповідності будь-якому з символів між ними. Якщо ви не помістите жодних символів між ними, це може призвести до помилки. Щоб знайти відповідність цим особливим символам, ми повинні екранувати їх, поставивши перед ними символ backslash\. Backslash (або зворотний слеш) це ще один спеціальний символ, який повідомляє движку regex, що треба шукати наступний символ буквально, а не використовувати його як метасимвол. Двигун regex шукатиме символи [і ]буквально, тільки якщо їм обом передуватиме зворотний слеш:
pattern: \[\]
string: Ви не можете match [] using regex! You will regret this!
matches:                  ^^ 
( Дивимося що вийшло цього разу ) ОК, а якщо ми хочемо знайти сам зворотний слеш? Відповідь проста. Оскільки backslash \теж є спеціальним символом, його теж потрібно екранувати. Чим? Зворотним слешем же!
pattern: \\
string: C:\Users\Tanja\Pictures\Dogs
matches:    ^ ^ ^ ^
( Той самий приклад насправді ) Тільки спеціальним символам повинен передувати backslash. Решта символів інтерпретуються буквально за умовчанням. Наприклад, регулярне вираз tбуквально відповідає лише літері tв нижньому регістрі:
pattern: t
string: tttt
matches: ^ ^ ^ ^
( Приклад ) Однак, така послідовність \tпрацює інакше. Вона є шаблоном для пошуку символу табуляції:
pattern: \t
string: tttt
matches:   ^ ^ ^
( Приклад ) Деякі поширені escape-послідовності включають \n(розриви рядків у стилі UNIX) і \r(використовуються в розривах рядків у стилі Windows, \r\n). \rє символом "повернення каретки", а \nє символом "перекладу рядка", обидва з яких були визначені разом зі стандартом ASCII, коли телетайпи ще перебували у повсюдному використанні. Інші поширені escape-послідовності будуть розглянуті у цьому посібнику пізніше.

А поки що закріпимо матеріал парою нескладних завдань:

Спробуйте написати регулярний вираз для пошуку... регулярного виразу ;) Результат повинен бути приблизно таким:
pattern:
string: ...match this regex ` \[\] ` with a regex?
matches:                       ^^^^	
( Рішення ) Впоралися? Молодці! А тепер спробуйте створити regex для пошуку таких escape-послідовностей:
pattern:
string: ` \r` , ` \t` , and ` \n` є all regex escape sequences.
matches:   ^^ ^^ ^^
( Рішення )

Крок 4: шукаємо "any" (будь-який) символ за допомогою точки.

RegEx: 20 коротких кроків для освоєння регулярних виразів.  Частина 1 - 5При написанні рішень для пошуку escape-послідовностей, які ми бачабо на попередньому кроці, ви, можливо, запитували себе: "Чи можу я зіставити символ зворотної косої риси, а потім будь-який інший символ, який слідує за ним?"... Звичайно можете! Є ще один спеціальний символ, який використовується для пошуку відповідності (майже) будь-якому символу – це символ точки (повної зупинки). Ось що він робить:
pattern: .
string: I'm sorry, Dave. I'm afraid I can't do that.
matches: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^	
( Приклад ) Якщо ви хочете порівняти тільки шаблони, які виглядають як escape-послідовності, ви можете зробити щось на зразок цього:
pattern: \\. 
string: Hi Walmart is my grandson є його name is " \n \r \t ".
matches:                                              ^^ ^^ ^^	
( Приклад ) І, як і з усіма спеціальними символами, якщо ви хочете зіставити літерал ., то вам потрібно поставити перед ним символ \:
pattern: \. 
string: War is Peace . Freedom is Slavery . Ignorance is Strength . 
matches:             ^ ^ ^
( Приклад )

Крок 5: діапазон символів

RegEx: 20 коротких кроків для освоєння регулярних виразів.  Частина 1 - 6Що, якщо вам потрібні не будь-які символи, а ви хочете знайти в тексті лише літери? Чи цифри? Чи голосні? Пошук за класами символів та їх діапазонами дозволить нам досягти цього.
` \n` , ` \r` , and ` \t` are whitespace characters, ` \. `, ` \\ ` and ` \[ `are not .	
Символи є "пробілами", якщо вони не створюють видимої позначки в тексті. Пробіл " " - це пробіл, розрив рядка чи табуляція. Припустимо, ми хочемо знайти escape-послідовності, що представляють лише пробельні символи \n, \rі \tу наведеному вище уривку, але не інші escape-послідовності. Як ми могли б це зробити?
pattern: \\[nrt] string 
: ` \n` , ` \r` , and ` \t` є whitespace characters, ` \. `, ` \\ ` and ` \[ `are not .
matches:   ^^ ^^ ^^	
( Приклад ) Це працює, але це не дуже елегантне рішення. Що, якщо нам потрібно буде зіставити escape-послідовність для символу " подача форми " , \f? (Цей символ використовується для позначення розривів сторінок у тексті.)
pattern: \\[nrt] 
string: ` \n` , ` \r` , ` \t` , and ` \f` are whitespace characters, ` \. `, ` \\ ` and ` \[ `are not .
matches:   ^^ ^^ ^^	
( Неробоче рішення ) При такому підході нам потрібно окремо перераховувати кожну малу літеру, яку ми хочемо зіставити, у квадратних дужках. Простіший спосіб зробити це - використовувати діапазони символів для відповідності будь-якій малі літері:
pattern: \\[az] 
string: ` \n` , ` \r` , ` \t` , and ` \f` є whitespace characters, ` \. `, ` \\ ` and ` \[ `are not .
matches:   ^^ ^^ ^^ ^^	
( А так вже працює ) Діапазони символів працюють так, як ви могли б очікувати з огляду на наведений вище приклад. Помістіть у квадратні дужки першу та останню літери, які ви хочете зіставити, з дефісом між ними. Наприклад, якщо ви хочете знайти тільки "комплекти" з backslash \і однієї літери від aдо m, Ви можете зробити наступне:
pattern: \\[am] 
string: ` \n` , ` \r` , ` \t` , and ` \f` are whitespace characters, ` \. `, ` \\ ` and ` \[ `are not .
matches:                         ^^	
( Приклад ) Якщо ви хочете порівняти кілька діапазонів, просто розмістіть їх впритул між квадратних дужок:
pattern: \[[a-gq-z] string 
: ` \n` , ` \r` , ` \t` , and ` \f` є whitespace characters, ` \. `, ` \\ ` and ` \[ `are not .
matches:         ^^ ^^ ^^	
( Приклад ) Інші загальні діапазони символів включають: A-Zі0-9

Випробуємо їх на практиці, і вирішимо пару завдань:

Шістнадцяткові числа можуть містити цифри 0-9, а також літери A-F. При використанні їх для вказівки кольорів шістнадцяткові коди можуть містити не більше трьох символів. Створіть регулярний вираз, щоб знайти дійсні шістнадцяткові коди у списку нижче:
pattern:
string: 1H8 4E2 8FF 0P1 T8B 776 42B G12
matches:      ^^^ ^^^ ^^^ ^^^	
( Рішення ) Використовуючи діапазони символів, створіть регулярний вираз, який вибиратиме лише малі приголосні (не голосні літери, включаючи y) у пропозиції нижче:
pattern:
. _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _  _ _ _ _
matches:   ^ ^ ^^^ ^ ^^ ^ ^^ ^ ^ ^ ^^^ ^ ^ ^^^ ^ ^^	
( Рішення )

Крок 6: not, caret, циркумфлекс, знак вставки... символ^

RegEx: 20 коротких кроків для освоєння регулярних виразів.  Частина 1 - 7Воістину, over 9000 імен цього символу :) Але, для простоти, мабуть зупинимося на "not". Моє рішення останнього завдання трохи довге. Потрібно було 17 символів, щоб сказати: "отримати весь алфавіт, крім голосних". Звичайно, є простіший спосіб зробити це. Знак "not" ^дозволяє нам визначати символи та діапазони символів, які повинні не відповідати вказаним у шаблоні. Простіше рішення останнього завдання, наведеного вище, полягає в тому, щоб знайти символи, які не позначають голосні літери:
pattern: [^aeiou] 
string:   Th e w a lls i n th e m a ll a r e t o t a lly, t o t a lly  t a ll. 
matches: ^^ ^^ ^^^^ ^^^^ ^^ ^^^ ^ ^^ ^ ^^^^^^ ^ ^^^^^ ^^^	
( Приклад ) Знак "not" ^як крайній лівий символ у квадратних дужках []вказує механізму регулярних виразів на збіг з одним (будь-яким) символом, якого немає у квадратних дужках. Це означає, що наведене вище регулярне вираження відповідає всім пробілам, точці ., коми ,і великої Tна початку пропозиції. Щоб виключити їх, ми можемо точно також помістити їх у квадратні дужки:
pattern: [^aeiou .,T] string  
: T e w a lls i n th e m a ll a r e t o t a lly , t o t a lly t a ll . 
matches:   ^ ^ ^^^ ^ ^^ ^ ^^ ^ ^ ^ ^^^ ^ ^ ^^^ ^ ^^	
( Приклад ) Зверніть увагу, що в цьому випадку, нам не потрібно екранувати точку зворотним слешем, як ми робабо раніше, коли шукали її, не користуючись при цьому квадратними дужками. Багато спеціальних символів у квадратних дужках обробляються буквально, включаючи відкритий [- але не ]символ дужки, що закриває (здогадуєтеся чому?). Символ зворотної косої межі \теж не трактується буквально. Якщо ви хочете порівняти літеральну (літеральну) зворотну косу межу \з використанням квадратних дужок, то ви повинні екранувати її, поставивши перед нею наступну зворотну косу межу \\. Така поведінка була призначена для того, щоб символи пробілів теж можна було розмістити у квадратних дужках для порівняння:
pattern: [\t]
string: tttt
matches:   ^ ^ ^
( Приклад ) Знак "not" ^також можна використовувати з діапазонами. Якби я хотів захопити тільки символи a, b, c, x, yі z, я міг би зробити наприклад так:
pattern: [abcxyz] 
string:   abc defghijklmnopqrstuvw xyz 
matches: ^^^ ^^^
( Приклад ) ... або, я міг би вказати, що я хочу знайти будь-який символ, який знаходиться не між dі w:
pattern: [^dw] 
string:   abc defghijklmnopqrstuvw xyz 
matches: ^^^ ^^^
( Приклад ) Однак,Будьте обережніз "не" ^. Легко подумати "ну, я вказав [^ b-f], тому я повинен отримати малий літеру aабо щось після f. Це не той випадок. Цей регулярний вираз буде відповідати будь-якому символу, що не входить в цей діапазон, включаючи літери, цифри, розділові знаки і пробіли.
pattern: [^dw] 
string:   abc defg h . i , j - klmnopqrstuvw xyz 
matches: ^^^ ^ ^ ^ ^ ^^^
( Приклад )

Завдання для прокачування:

Використовуйте знак "not" ^у квадратних дужках, щоб зіставити всі слова нижче, які не закінчуються на y:
pattern:
string: day dog ​​hog hay bog bay ray rub 
матчі:      ^^^ ^^^ ^^^ ^^^	
( Рішення ) Напишіть регулярний вираз, використовуючи діапазон і знак "not" ^, щоб знайти всі роки між 1977 і 1982 (включно):
pattern:
string: 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984
matches:            ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ ^^^^
( Рішення ) Напишіть регулярний вираз для пошуку всіх символів, які не є символом "not" ^:
pattern:
string:   abc1 ^ 23*() 
matches: ^^^^ ^^^^^	
( Рішення )

Крок 7: класи символів

Класи символів навіть простіші, ніж діапазони символів. Різні двигуни регулярних виразів мають різні доступні класи, тому тут я розповім тільки про основні. (Перевірте, яку версію regex ви використовуєте, тому що їх може бути більше - або вони можуть відрізнятися від показаних тут.) Класи символів працюють майже як діапазони, але при цьому ви не можете вказати значення 'start' та 'end':
клас символи
\d "цифри"[0-9]
\w "символи слова"[A-Za-z0-9_]
\s "прогалини"[ \t\r\n\f]
Клас символів \w"word" особливо корисний, оскільки цей набір символів часто потрібний для допустимих ідентифікаторів (імен змінних, функцій і т.д.) у різних мовах програмування. Ми можемо використовувати \w, щоб спростити регулярний вираз, який ми бачабо раніше:
pattern: \\[az] 
string: ` \n` , ` \r` , ` \t` , and ` \f` є whitespace characters, ` \. `, ` \\ ` and ` \[ `are not .
matches:   ^^ ^^ ^^ ^^	
Використовуючи \wми можемо написати так:
pattern: \\w 
string: ` \n` , ` \r` , ` \t` , and ` \f` are whitespace characters, ` \. `, ` \\ ` and ` \[ `are not .
matches:   ^^ ^^ ^^ ^^	
( Приклад )

2 завдання для успіху:

Як ми з вами знаємо, Java ідентифікатор (ім'я змінної, класу, функції і т.д.) може починатися тільки з літери a- zA- Z, знака долара $або підкреслення _. ( підкреслення, звичайно поганий стиль, але компілятор пропускає, прим. перекладача ). Решта символів має бути символами "word" \w. Використовуючи один або кілька класів символів, створіть регулярний вираз для пошуку допустимих ідентифікаторів Java серед наступних трисимвольних послідовностей:
pattern:
string:   __e $12 .x2 foo Bar 3mm
matches: ^^^ ^^^ ^^^ ^^^	
( Рішення ) Номери соціального страхування США (SSN) є 9-значними номерами у форматі XXX-XX-XXXX, де кожен X може бути будь-якою цифрою [0-9]. Використовуючи один або кілька класів символів, напишіть регулярний вираз, щоб знайти правильно відформатовані номери SSN у списку нижче:
pattern:
string: 113-25=1902 182-82-0192 H23-_3-9982 1I1-O0-E38B
matches:              ^^^^^^^^^^^^
( Рішення ) RegEx: 20 коротких кроків для освоєння регулярних виразів. Частина 2. 20 коротких кроків освоєння регулярних виразів. Частина 3. RegEx: 20 коротких кроків для освоєння регулярних виразів. Частина 4
Коментарі
  • популярні
  • нові
  • старі
Щоб залишити коментар, потрібно ввійти в систему
Для цієї сторінки немає коментарів.