Technology Pug
Регулярні вирази у мовах програмування — потужний, але складний в опануванні інструмент. Тому не дивно, що багато хто відкладає його на потім або намагається використовувати по мінімуму.
Але це найкращий спосіб опрацювання текстів, а також метод розв’язання завдань, які пов’язані з пошуком, редагуванням, заміною тексту у файлах. Тому регулярні вирази варто знати. Сьогодні мова піде про регулярні вирази в популярній кросплатформенній мові Java.
Зміст
Регулярні вирази в Java — це певні послідовності символів, за допомогою яких можна обробляти рядки тексту за спеціальними синтаксичними шаблонами.
Приклад регулярних виразів має такий вигляд:
String regex="java"; // шаблон рядка "java"; String regex="\\d{3}"; // шаблон рядка з трьох цифрових символів;
Ця методика дає змогу дізнатися, чи входить певний символ або їхня послідовність у рядок. Інакше кажучи, це методика для обробки рядків.
Наприклад, вона може застосовуватися, якщо потрібно перевірити коректність введення електронної пошти. У ньому обов’язково має бути присутнім символ @, адреса домену, крапка після нього і доменна зона. Тобто система перевіряє, щоб адреса виглядала як user@gmail.com (сама адреса без лапок, зрозуміло), а не user.gmail.com або user@gmail,com, або навіть user@gmail.com.
Клас Java, який називається Pattern — це базове рішення для роботи з регулярними виразами в Java. Саме його використовують при підключенні RegEx до коду програми.
Цей клас можна використовувати двома різними способами (методами). По-перше, це Pattern.matches()
. Він застосовується для швидкої перевірки тексту на відповідність заданому регулярному виразу. Але він перевіряє тільки один текст або рядок.
По-друге, це Pattern.compile()
— скомпільований екземпляр Pattern. Ось його вже можна використовувати кілька разів, щоб скласти регулярний вираз для кількох текстів.
Наприклад:
String regex="java"; // шаблон рядка "java"; String regex="\\d{3}"; // шаблон рядка з трьох цифрових символів;
Ще один клас Java для регулярних виразів — Matcher (java.util.regex.Matcher) — він необхідний для пошуку декількох входжень того чи іншого набору символів у межах одного тексту, а також застосовується для пошуку в різних текстах, які подаються на вхід у межах одного шаблону. У ньому є низка своїх методів, які використовуються для роботи.
Серед основних відзначимо такі:
boolean matches()
: цей метод повертає значення true
у разі збігу рядка з шаблоном;boolean find()
: цей метод повертає значення true
у разі виявлення підрядка, що збігається з шаблоном, після чого перейде до нього;int start()
: цей метод повертає значення індексу відповідності;int end()
: використовуючи цей метод, можна отримати показники індексу відповідності;String replaceAll(String str)
: а ось цей метод виводить значення, яке задається підрядком str
при зміні основного рядка.А ось такий вигляд має приклад із використанням Pattern і Matcher:
імпорт java.util.regex.Matcher; import java.util.regex.Pattern; public class Main { public static void main (String[] args) { Pattern pattern1 = Pattern.compile ("[x-z]+");//Пошук відбуватиметься від x до z включно. //Пошук відбуватиметься тільки за символами нижнього регістру. //Щоб вимкнути чутливість до регістру, можна використовувати Pattern.CASE_INSENSITIVE. Matcher matcher1 = pattern1.matcher ("x y z 1 2 3 4 "); System.out.println (matcher1.find()); //Пошук будь-якого збігу з шаблоном. //Виводиться значення true, оскільки в рядку є символи шаблону. Matcher matcher2 = pattern1.matcher ("X Y Z 1 2 3 4"); System.out.println (matcher2.find()); //Виводиться значення false. //Так як у рядку немає символів, що підходять за шаблоном. Шаблон pattern2 = Pattern.compile ("[a-zA-Z0-9]"); //Додається пошук за символами нижнього і верхнього регістру, а також цифр. Matcher matcher3 = pattern2.matcher ("A B C D X Y Z a b c d x y z 1 2 3 4"); System.out.println (matcher3.find()); //Виводиться значення true
Ще один клас — PatternSyntaxException. Він виводить повідомлення про неперевірене виключення, якщо в синтаксисі регулярного виразу припустилися помилки. Йдеться про некоректні символи в шаблоні, наприклад, про друкарську помилку.
Клас оголошується ось так:
public class PatternSyntaxException extends IllegalArgumentException
У переліку методів класу відзначимо такі:
getDescription ()
: метод отримує опис помилок;int getIndex ()
: цей метод отримує індекс помилки;getMessage ()
: у цьому методі повертається багаторядковий рядок, що містить опис помилки, індекс, шаблон із помилкою та навіть візуально показує, де в шаблоні допущена помилка;getPattern ()
: цей метод, своєю чергою, отримує помилковий шаблон регулярного виразу.Приклад класу має такий вигляд:
Жива демонстрація package com.tutorialspoint; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; public class PatternSyntaxExceptionDemo { private static String REGEX = "[""; private static String INPUT = "Собака каже мяу" + "Усі собаки кажуть мяу."; private static String REPLACE = "cat"; public static void main(String[] args) { try{ Pattern pattern = Pattern.compile(REGEX); // отримати об'єкт matcher Matcher matcher = pattern.matcher(INPUT); INPUT = matcher.replaceAll(REPLACE); } catch(PatternSyntaxException e){ System.out.println("PatternSyntaxException: "); System.out.println("Description: "+ e.getDescription()); System.out.println("Index: "+ e.getIndex()); System.out.println("Message: "+ e.getMessage()); System.out.println("Pattern: "+ e.getPattern()); } } }
Для створення регулярного виразу задіюються рядки або об’єкти класу String. Але далеко не кожен рядок автоматично може скомпілюватися в регулярний вираз. Він має бути відповідним чином написаний — з використанням синтаксису, який визначається в офіційних специфікаціях Java.
У цьому разі йдеться про використання букв, цифр і метасимволів, які мають спеціальне значення саме в рамках регулярних виразів.
Синтаксичні конструкції регулярних виразів, як сказано вище, охоплюють літерні, цифрові та метасимволи.
Серед них:
Для пошуку меж рядків, слів і тому подібних даних використовуються такі метасимволи:
^
— метасимвол початку оброблюваного рядка;$
— метасимвол закінчення оброблюваного рядка;-
— так задається метасимвол, який має бути поза дужками, причому він повинен бути тільки один;\b
— таким чином задається закінчення слова;\B
— так задається умова, коли слово не закінчене;\A
— так задається старт введення;\Z
— так задається закінчення введення.Також можна вибирати певні класи символів:
\d
— будь-який цифровий символ;\D
— будь-який нецифровий;\s
— символ пробілу;\S\
— символ, що не має пробілу;.
— задати один довільний символ;\w
— абетково-цифровий символ;\W
— будь-який символ, за винятком абетково-цифрового.Для завдання діапазону можна використовувати -
, у цьому разі регулярний вираз (a-z) шукатиме всі символи в заданому діапазоні.
Серед інших способів використання косої риски відзначимо:
\n
— перенесення рядка; \\+
— екранування символу, оскільки коса риска використовується як спецсимвол.Детальніше про це поговоримо нижче у відповідному розділі.
Приклад найпростішого регулярного виразу для перевірки адреси електронної пошти на правильність має такий вигляд:
^[A-Z0-9+_.-]+@[A-Z0-9.-]+$
Тут перевіряється входження символу @
, крапки-роздільника і доменної зони, які є обов’язковими для електронної пошти.
А ось так виглядає складніший приклад, який шукає цифрові символи в рядку:
імпорт java.util.regex.Matcher; import java.util.regex.Pattern; public class RegexMatches { public static void main( String args[] ) { // Рядок для сканування, щоб знайти шаблон String str = "Хрещення Київської Русі відбулося в 988 році! Чи не так?"; String pattern = "(.*)(\\d+)(.*)"; // Створення Pattern об'єкта Pattern r = Pattern.compile(pattern); // Створення matcher об'єкта Matcher m = r.matcher(str); if (m.find( )) { System.out.println("Знайдено значення: " + m.group(0)); System.out.println("Знайдено значення: " + m.group(1)); System.out.println("Знайдено значення: " + m.group(2)); }інакше { System.out.println("НЕ Збігається"); } } }
На виході отримаємо такий результат:
Крім символів у регулярних виразах застосовуються квантифікатори. Це обмежувачі, за допомогою яких задається частота появи певного символу або декількох. Їх потрібно записувати після самих символів.
Основні квантифікатори:
?
— символ не з’являється зовсім або ж з’являється лише раз;-
— символу зовсім немає в рядку або він з’являється, або з’являється більше ніж 0 разів;+
— символ з’являється щонайменше двічі або більшу кількість разів;{n}
— символ з’являється задане число разів (n разів);{n,}
— символ з’являється задане число разів з умовою (n і більше);{n,m}
— не менше n, але не більше m разів.Квантифікатори можуть функціонувати в одному з трьох режимів: жадібному, наджадібному та ледачому. Базовий — жадібний режим — саме в ньому регулярні вирази працюють за замовчуванням.
У жадібному режимі програма буде шукати символи максимальної довжини, що збігаються в рамках рядка. Прохід здійснюється спочатку зліва направо, а потім справа наліво.
Наджадібний режим функціонує подібним чином, але він не використовує зворотний прохід (коли перевірка рядка йде справа наліво) — так званий реверсивний пошук. Це в деяких випадках дає змогу прискорити процес.
Лінивий режим шукає найкоротше входження символів, які збігаються, та задовольняє всім умовам, заданим у пошуковому шаблоні.
Давайте перейдемо до прикладів.
Ось такий вигляд має жадібний режим:
"A.+a"// Шукає максимальний за довжиною збіг у рядку. //Приклад жадібного квантифікатора import java.util.regex.Matcher; import java.util.regex.Pattern; public class Main { public static void main(String[] args) { Pattern p = Pattern.compile("a+"); Matcher m = p.matcher("aaa"); while (m.find()) System.out.println("Шаблон знайдено з " + m.start() + " to " + (m.end()-1))); } }
На виході буде таке:
Pattern found from 0 to 2
Наджадібний режим:
"А.++а"?"// Працює так само, як і жадібний режим, але не здійснює реверсивний пошук під час захоплення рядка. // Приклад наджадібного квантифікатора import java.util.regex.Matcher; import java.util.regex.Pattern; public class Main { public static void main(String[] args) { Pattern p = Pattern.compile("a++"); Matcher m = p.matcher("aaa"); while (m.find()) System.out.println("Шаблон знайдено з " + m.start() + " to " + (m.end()-1))); } }
На виході буде таке:
Pattern found from 0 to 2
Ледачий режим:
"A.+?a"// Шукає найкоротший збіг. //Приклад ледачого квантифікатора import java.util.regex.Matcher; import java.util.regex.Pattern; public class Main { public static void main(String[] args) { Pattern p = Pattern.compile("g+?"); Matcher m = p.matcher("ggg"); while (m.find()) System.out.println("Шаблон знайдено з " + m.start() + " to " + (m.end()-1))); } }
Висновок буде таким:
Pattern found from 0 to 0 Pattern found from 1 to 1 Pattern found from 2 to 2
У цьому розділі ми розглянемо деякі приклади, які допоможуть зрозуміти, як все це працює на ділі.
Раніше ми згадували, що один із базових прикладів — перевірка адреси електронної пошти на валідність і коректність. Тобто щоб стояв символ @
, крапка і доменна зона.
Ось так ця перевірка має вигляд у коді:
List emails = new ArrayList(); emails.add("name@gmail.com"); //Неправильний імейл: emails.add("@gmail.com"); String regex = "^[A-Za-z0-9+_.-]+@(.+)$"; Pattern pattern = Pattern.compile(regex); for(String email : emails){ Matcher matcher = pattern.matcher(email); System.out.println(email +" : "+ matcher.matches()); } Результат: name@gmail.com : true @gmail.com : false
Цей регулярний вираз перевіряє валідність номера телефону. Виглядає він так:
import java.util.regex.Matcher; import java.util.regex.Pattern; public class ValidatePhoneNumber { public static void main(String[] argv) { String sPhoneNumber = "605-8889999"; // String sPhoneNumber = "605-88899991"; // String sPhoneNumber = "605-888999A"; Pattern pattern = Pattern.compile("\d{3}-\d{7}"); Matcher matcher = pattern.matcher(sPhoneNumber); if (matcher.matches()) { System.out.println("Phone Number Valid"); } іще { System.out.println("Номер телефону повинен бути у формі XXX-XXXXXXXXX"); } } }
А ось клас для визначення валідності IP-адреси, записаної в десятковому вигляді:
private static boolean checkIP(String input) { return input.matches("((0|1\\d{0,2}|2([0-4][0-9]|5[0-5]))\\.){3}(0|1\\d{0,2}|2([0-4][0-9]|5[0-5]))"); }
За правилами, кількість відкритих дужок має збігатися з кількістю закритих, оскільки в іншому випадку порушується логіка роботи. Це перевіряється так:
private static boolean checkExpression(String input) { Pattern pattern = Pattern.compile("\\([\\d+/*-]*\\)"); Matcher matcher = pattern.matcher(input); do { input = matcher.replaceAll(""); matcher = pattern.matcher(input); } while (matcher.find()); return input.matches("[\\d+/*-]*"); }
Тепер спробуємо витягти дату з рядка. Це робиться таким чином:
private static String[] getDate(String desc) { int count = 0; String[] allMatches = new String[2]; Matcher m = Pattern.compile("(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.](19|20)\\d\\\d").matcher(desc); while (m.find()) { allMatches[count] = m.group(); count++; } return allMatches; }
Перевірка:
public static void main(String[] args) throws Exception{ String[] dates = getDate("coming from the 25/11/2020 to the 30/11/2020"); System.out.println(dates[0]); System.out.println(dates[1]); }
Результат:
25/11/2020 30/11/2020
Як бачимо, регулярні вирази Java широко використовуються і дають змогу реалізовувати перевірки на коректність даних на льоту, хоча багато програмістів не люблять їх через складність. Але в умілих руках це потужний засіб для пошуку даних, роботи з рядками тощо.
Також ознайомитися з регулярними виразами можна у відео:
Резиденти Дія.City сплатили до бюджету понад 8 млрд грн податків в І кварталі 2025 року.…
У Китаї закликають офісних працівників не працювати надто багато — держава сподівається, що вільний час…
Експерти звертають увагу на тривожну тенденцію: люди все частіше використовують ChatGPT, щоб визначити місцезнаходження, зображене…
Компанія JetBrains випустила нову версію мультимовного середовища розробки IntelliJ IDEA 2025.1. Оновлена IDE отримала численні…
Платформа обміну миттєвими повідомленнями Discord впроваджує функцію перевірки віку за допомогою сканування обличчя. Зараз вона…
Wikipedia намагається захистити себе від тисяч різноманітних ботів-скрейперів, які сканують дані цієї платформи для навчання…