RegEx: 20 коротких кроків для освоєння регулярних виразів. Частина 1 Оригінал тут Минулої частини ми освоїли найпростіші регулярні висловлювання, і вже дечому навчабося. У цій частині ми вивчимо трохи більш складні конструкції, але, повірте, це буде не так важко, як могло б здатися. Отже, продовжимо!
Крок 8: зірочка
Досі нам більш-менш вдавалося зіставляти лише рядки заданої довжини. Але в останніх завданнях ми наблизабося до межі того, що ми можемо зробити за допомогою позначень, які ми бачабо й досі. Припустимо, наприклад, що ми не обмежені 3-символьними ідентифікаторами Java, а ми можемо мати ідентифікатори будь-якої довжини. Рішення, яке могло працювати в попередньому прикладі, не працюватиме в наступному прикладі:
Крок 9: "опційний" знак питання
Ви вже написали regex для вирішення останнього завдання? Це спрацювало? Тепер спробуйте застосувати його тут:
Крок 10: знак "or" (або)
На кроці 8 у нас виникли деякі труднощі зі знаходженням різних типів чисел з плаваючою точкою:
Крок 8: зірочка *
та знак "плюс"+
Досі нам більш-менш вдавалося зіставляти лише рядки заданої довжини. Але в останніх завданнях ми наблизабося до межі того, що ми можемо зробити за допомогою позначень, які ми бачабо й досі. Припустимо, наприклад, що ми не обмежені 3-символьними ідентифікаторами Java, а ми можемо мати ідентифікатори будь-якої довжини. Рішення, яке могло працювати в попередньому прикладі, не працюватиме в наступному прикладі:
pattern: [a-zA-Z_$]\w\w string: __e $12 3 3.2 fo Bar r a23 mm ab x matches: ^^^ ^^^ ^^^ ^^^( Приклад ) Зверніть увагу, що коли ідентифікатор дійсний, але довше 3 символів, порівнюються лише перші три символи. І коли ідентифікатор є дійсним, але містить менше 3 символів, то regex його взагалі не знаходить! Проблема в тому, що вирази в квадратних дужках
[]
відповідають одному символу, як і класи символів, такі як \w
. Це означає, що будь-які збіги в наведеному вище регулярному виразі повинні бути рівно в три символи. Так що це не працює, як ми могли б сподіватися. Тут можуть допомогти спеціальні символи *
та +
. Це модифікатори, які можуть бути додані праворуч від будь-якого виразу, щоб шукати відповідності до цього виразу більше одного разу. Зірка Кліні (або "зірочка")*
вкаже, що потрібно шукати відповідності попередньому токену будь-яку кількість разів, включаючи нуль разів. Знак "плюс" +
вкаже, що потрібно шукати один чи кілька разів. Таким чином, вираз, який передує +
, є обов'язковим (принаймні один раз), у той час як вираз, який передує *
, є необов'язковим, але коли він з'являється, він може з'являтися будь-яку кількість разів. Тепер, з цим знанням ми можемо виправити наведений вище регулярний вираз:
pattern: [a-zA-Z_$]\w* string: __e $123 3.2 fo Barr a23mm ab x матчі: ^^^ ^^^^ ^^ ^^^^ ^^^^^ ^^ ^( Приклад ) Тепер ми зіставляємо дійсні ідентифікатори будь-якої довжини! Бінґо! Але що б сталося, якби ми в прикладі вище використовували
+
замість *
?
pattern: [a-zA-Z_$]\w+ string: __e $123 3.2 fo Barr a23mm ab x matches: ^^^ ^^^^ ^^ ^^^^ ^^^^^ ^^( Приклад ) Ми пропустабо останній збіг
х
,. Це з тим, що це потрібно +
зіставлення хоча б одного символу, але оскільки вираз у дужках []
, попереднє \w+
, вже 'з'їло' символ x
, то доступних символів більше залишилося, тому зіставлення зірвалася. Коли ми можемо використовувати +
? Коли нам потрібно знайти хоча б один збіг, але не важливо, скільки разів повинен збігатися цей вислів. Наприклад, якщо ми хочемо знайти будь-які числа, що містять десяткову точку:
pattern: \d*\.\d+ string: 0.011 .2 42 2.0 3.33 4.000 5 6 7.89012 matches: ^^^^^ ^^ ^^^ ^^^^ ^^^^^ ^^^^^^^( Приклад ) Зверніть увагу, Що зробивши числа зліва від десяткової точки необов'язковими, ми змогли знайти як 0.011 так і .2. Для цього нам потрібно було зіставити рівно одну десяткову точку за допомогою
\.
і щонайменше одну цифру праворуч від десяткової точки за допомогою \d+
. Вищезгаданий регулярний вираз не буде відповідати числу, подібному 3.
, тому що для відповідності нам потрібно принаймні одна цифра праворуч від десяткової точки.
За традицією, вирішимо кілька простих завдань:
Знайдіть усі англійські слова у уривку нижче.pattern: string: 3 plus 3 is six but 4 plus three is 7 matches: ^^^^ ^^ ^^^ ^^^ ^^^^ ^^^^^ ^^( Рішення ) Знайдіть усі позначення розмірів файлів у списку нижче. Розміри файлів будуть складатися з числа (з десятковою точкою або без неї), за яким слідують
KB
, MB
, GB
або TB
:
pattern: string: 11TB 13 14.4MB 22HB 9.9GB TB 0KB matches: ^^^^ ^^^^^^ ^^^^^ ^^^( Рішення )
Крок 9: "опційний" знак питання?
Ви вже написали regex для вирішення останнього завдання? Це спрацювало? Тепер спробуйте застосувати його тут:
pattern: string: 1..3KB 5...GB ..6TB matches:Очевидно, що жодне з цих позначень не є допустимим розміром файлу, тому хороший регулярний вираз не повинен знаходити жодного з них. Рішення, яке я написав для вирішення останнього завдання, відповідає їм усім, принаймні частково:
pattern: \d+\.*\d*[KMGT]B string: 1..3KB 5...GB .. 6TB matches: ^^^^^^ ^^^^^^^ ^^^( Приклад ) То в чому проблема? Насправді нам потрібно знайти тільки одну десяткову точку, якщо вона є. Але
*
допускає будь-яку кількість збігів, включаючи нуль. Чи є спосіб зіставляти лише нуль разів чи один раз? Але чи не більше одного разу? Звичайно є. "optional" ?
це модифікатор, який відповідає нулю або одному з попередніх символів, але не більше:
pattern: \d+\.?\d*[KMGT]B string: 1.. 3KB 5...GB .. 6TB matches: ^^^ ^^^( Приклад ) Ми тут підійшли до рішення, але це ще не зовсім те, що нам треба. Трохи згодом ми побачимо, як це виправити, за кілька кроків.
А поки що вирішимо таке завдання:
У деяких мовах програмування (наприклад, Java) за деякими цілими числами та числами з плаваючою комою (точкою) можуть слідуватиl
/ L
та f
/ F
, щоб вказати, що вони повинні розглядатися як long / float (відповідно), а не як звичайні int / double. Знайдіть усі дійсні "long" числа в рядку нижче:
pattern: string: 13L long 2l 19 L lL 0 матчів: ^^^ ^^ ^^ ^( Рішення )
Крок 10: знак "or" (або)|
На кроці 8 у нас виникли деякі труднощі зі знаходженням різних типів чисел з плаваючою точкою:
pattern: \d*\.\d+ string: 0.011 .2 42 2.0 3.33 4.000 5 6 7.89012 matches: ^^^^^ ^^ ^^^ ^^^^ ^^^^^ ^^^^^^^Наведений вище шаблон зіставляє числа з десятковою точкою і щонайменше одну цифру праворуч від десяткової точки. Але що, якщо ми хочемо порівняти такі рядки, як
0.
? (Без цифр праворуч від десяткової точки.) Ми могли б написати такий регулярний вираз:
pattern: \d*\.\d* string: 0.011 .2 42 2.0 3.33 4.000 5 6 7.89012 0. . matches: ^^^^^ ^^ ^^^ ^^^^ ^^^^^ ^^^^^^^ ^^ ^( Приклад ) Це відповідає
0.
, але це також відповідає одиночній точці .
, як ви можете бачити вище. Насправді те, що ми намагаємося зіставити, це два різні класи рядків:
- числа з мінімум однією цифрою праворуч від десяткової точки
- числа з хоча б однією цифрою зліва від десяткової точки
pattern: \d*\.\d+ string: 0.011 .2 42 2.0 3.33 4.000 5 6 7.89012 0. . matches: ^^^^^ ^^ ^^^ ^^^^ ^^^^^ ^^^^^^^
pattern: \d+\.\d* string: 0.011 .2 42 2.0 3.33 4.000 5 6 7.89012 0. . matches: ^^^^^ ^^^ ^^^^ ^^^^^ ^^^^^^^^ ^^Ми бачимо, що в жодному з цих випадків підрядки
42
, 5
або 6
не .
знаходяться двигуном. Для отримання необхідного результату нам не завадило б об'єднати ці регулярки. Як ми можемо досягти цього? Знак "or" |
дозволяє нам вказати у регулярному вираженні відразу кілька можливих послідовностей збігів. Подібно до того, як []
дозволяє нам вказувати альтернативні одиночні символи, за допомогою знака "or" |
ми можемо вказувати альтернативні багатосимвольні вирази. Наприклад, якщо ми хочемо знайти "собаку" або "кішку", ми могли б написати якось так:
pattern: \w\w\w string: Obviously , a dog is a better pet t a n a cat . matches: ^^^^^^^^^^ ^^^ ^^^^^^ ^^^ ^^^ ^^^( Приклад ) ... але це відповідає всім потрійним послідовностям символів класу "word". Але "dog" та "cat" навіть не мають спільних букв, тому і квадратні дужки не допоможуть нам тут. Ось найпростіший регулярний вираз, який ми могли б використати, він відповідає обом і лише цим двом словам:
pattern: dog|cat string: Obviously, dog is better pet than a cat . matches: ^^^ ^^^( Приклад ) Механізм регулярних виразів спочатку намагається зіставити всю послідовність ліворуч від знака
|
, але якщо йому це не вдається, то потім він намагається зіставити послідовність праворуч від знака |
. Декілька знаків |
також можуть бути об'єднані в ланцюжки для відповідності більш ніж двом альтернативним послідовностям:
pattern: dog|cat|pet string: Авжеж, a dog is better pet than a cat . matches: ^^^ ^^^ ^^^( Приклад )
Тепер вирішимо чергову пару завдань, щоб краще засвоїти цей крок:
Використовуйте знак|
, щоб виправити десятковий регулярний вираз, вказаний вище, і отримати такий результат:
pattern: string: 0.011 .2 42 2.0 3.33 4.000 5 6 7.89012 0. . matches: ^^^^^ ^^ ^^^ ^^^^ ^^^^^ ^^^^^^^ ^^( Рішення ) Використовуйте знак
|
, класи символів, " optional " ?
тощо., щоб створити одне регулярне вираз, відповідне як цілим числам, і числам з плаваючою комою (точкою), як обговорювалося у завданню наприкінці попереднього кроку (це завдання трохи складніше, так ;))
pattern: string: 42L 12 x 3.4f 6l 3.3 0F LF .2F 0. matches: ^^^ ^^ ^^^^ ^^ ^^^ ^^ ^^^ ^^( Рішення ) 20 коротких кроків для освоєння регулярних виразів. Частина 3 RegEx: 20 коротких кроків для освоєння регулярних виразів. Частина 4