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:
import 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. //Так как в строке нет символов, подходящих по шаблону. Pattern 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 ()
: этот метод, в свою очередь, получает ошибочный шаблон регулярного выражения.Пример класса выглядит так:
Live Demo 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 = "The dog says meow " + "All dogs say meow."; private static String REPLACE = "cat"; public static void main(String[] args) { try{ Pattern pattern = Pattern.compile(REGEX); // get a matcher object 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.-]+$
Здесь проверяется вхождение символа @
, точки-разделителя и доменной зоны, которые обязательны для электронной почты.
А вот так выглядит более сложный пример, который ищет цифровые символы в строке:
import 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)); }else { 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("Pattern found from " + 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("Pattern found from " + 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("Pattern found from " + 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"); } else { System.out.println("Phone Number must be in the form XXX-XXXXXXX"); } } }
А вот класс для определения валидности 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 широко используются и позволяют реализовывать проверки на корректность данных на лету, хотя многие программисты не любят их из-за сложности. Но в умелых руках это мощное средство для поиска данных, работы со строками и так далее.
Также ознакомиться с регулярными выражениями можно в видео:
Прокси (proxy), или прокси-сервер — это программа-посредник, которая обеспечивает соединение между пользователем и интернет-ресурсом. Принцип…
Согласитесь, было бы неплохо соединить в одно сайт и приложение для смартфона. Если вы еще…
Повсеместное распространение смартфонов привело к огромному спросу на мобильные игры и приложения. Миллиарды пользователей гаджетов…
В перечне популярных чат-ботов с искусственным интеллектом Google Bard (Gemini) еще не пользуется такой популярностью…
Скрипт (англ. — сценарий), — это небольшая программа, как правило, для веб-интерфейса, выполняющая определенную задачу.…
Дедлайн (от англ. deadline — «крайний срок») — это конечная дата стачи проекта или задачи…