01 января 2008

Регулярные выражения в Java

В данной статье будет рассмотрена работа с регулряными выражениями в Java, а именно пакет java.util.regex, который состоит из трёх классов.
Классы, которые позволяют сравнить текстовую строку, с указанным шаблонным регулярным выражением.
Регулярные выражения (англ. regular expressions, жарг. регэкспы или регексы) ― современная система поиска текстовых фрагментов в электронных документах, основанная на специальной системе записи образцов для поиска.
Рассмотрим классы, используемые в работе с регулярными выражениями:
- Pattern - скомпилированное представление регулярного выражения.
- Matcher - движок, который проводит операции сравнения между шаблоном (регулярным выражением) и указанной строкой.
- PatternSyntaxException - исключение генерируемое в случае синтаксических ошибок в регулярном выражении.
Итак, как уже было сказано выше, для того, что-бы использовать регулярное выражение (класс Pattern), мы вначале должны задать его с помощью строки, потом скомпилировать эту строку путём вызова статистического метода compile() класса Pattern. В результате мы получаем готовое для работы регулярное выражение. Для сравнения строки с регулярным выражением используем метод matcher() класса Matcher. Проверить результат сравнения можна с помощью метода matches() этого же класса.
Рассмотрим простой пример
Pattern p = Pattern.compile("1*0");
Matcher m = p.matcher("111110");
boolean b = m.matches();
Как видим в первой строке создаётся регулярное выражение, которое соответствует строке любой длинны, которая должна начинатся из последовательности единицц и должна заканчиваеться нулём. Во второй строке сравниваем наше регулярное выражение с указанной строкой. В результате сравнения переменная b в третьей строке примет значение true.
Рассмотрим найболее часто встречаемые конструкции регулярный выражений:

\\ - обратный слеш
\t - символ табуляции
\n - переход на новую строку
\r - возврат каретки
\e - символ Esc
\0n - символ в восьмиричной системе отсчёта 0n (0<=n<=7)
\xhh - символ в 16-ричной системе отсчёта 0xhh
\uhhhh - символ в 16-ричной системе отсчёта 0xhhhh

[150] - символ может принимать значение 1 , 5 либо 0
[^45] - символ может принимать любые значения, кроме 4 и 5
[0-9_a-z] - символ может принимать значение от 0 до 9 ЛИБО от a до z
[1-9&&[^4-6]] - символ может принимать значения от 1, до 9, кроме 4,5, 6.

. - любой символ
\d - цифра от 0 до 9: [0-9]
\D - не цифра : [^0-9]
\s - символ "пробела" : [ \t\n\x0B\f\r]
\S - [^\s]
\w - литера английского алфавита либо цифра A word character: [a-zA-Z0-9]
\W - [^\w]

X* - символ X встречается один или более раз
X? - символ Х встречается один раз или ни разу
X+ - символ Х встречается один или более раз
X{n} - символ Х встречается в точности n раз
X{n,} - символ Х встречается не меньше n раз
X{n,m} - символ Х встречается не меньше n раз, но не больше m раз

Это далеко не полный перечень регулярных конструкций, которые могут использоватся для распознавания строк.
С учётом рассмотренных регулярных конструкций попробуем написать функцию, которая с помощью регулярных выражений будет распознавать правильность ввода электронного адреса:

public static boolean testEmail(String email){
Pattern p = Pattern.compile("(([a-zA-Z][\\w]*)@[\\w[.]]*\\.+([a-z]+))");
Matcher m = p.matcher(email);
boolean b = m.matches();
return b;
}


Итак, каждый электронный адрес должен начинатся из символа латинского алфавита, а после могут следовать другие символы латинского алфавита, либо цифри, хотя их может и не быть (логин длинной 1 тоже допустим). Обезательный символ комерческае Эт (собачка). И последняя часть доменное имя: слова в перемешку с цифрами разделенные точками, и заканчивающееся 2мя либо тремя буквами латинского алфавита (ru, ua, com , net и т.д.).
Для того что бы протестировать данную функцию можно использовать следующий метод:

public static void main(String[] args) {
String email1="K1ngAr2r@ukr.mail.net";
String email2="1ngr1t@ukr.mail.net";
String email3="N1fN1f@ukr.mail .";
System.out.print(""+
email1+" is "+(testEmail(email1)?"good":"bad")+" email" + "\n" +
email2+" is "+(testEmail(email2)?"good":"bad")+" email" + "\n" +
email3+" is "+(testEmail(email3)?"good":"bad")+" email" + "\n"
);
}


Первый электронный адрес буде соответвовать шаблону, а вот остальные 2 не подойдут.
Вероятно вы обратили внимание на расставленные скобки, хоть они нигде и не используются. Дело в том, что с помощью этих скобок мы разгрупировали наше выражение и теперь используя функцию group из класса Matcher мы можем получать доступ к части выражения, например: m.group(1) - вернёт нам всё выражение(скобки охватывающие всё выражение), а m.group(2) - имя учётной записи, до символа "@" , вторые обработанные компилятором скобки и т.д.

В качестве упражнения можете попробывать написать функцию, которая будет проводить валидацию URL ареса, а также выделять название доменного имени первого уровня.

для более подробной информации:
java.util.regex

5 комментариев:

Ольга комментирует...

"X* - символ X встречается один или более раз"

По моему "*" это когда символ встречается 0 или более раз

Анонимный комментирует...

да. Когда есть "*" - это значит любое количество любых символов. В том числе их может и не быть.

новичок комментирует...

а как насчет случая когда после собачки идет сразу точка?
Например: hello@.mail.ru
Программа выдаст: hello@.mail.ru is good email

так не пойдет.

Riddler комментирует...

Спасибо! Очень легко воспринялось.

Gerz комментирует...

Pattern p = Pattern.compile("([a-zA-Z][\\w]*)@([a-zA-Z][\\w]*[.])*([a-zA-Z][\\w]*[.][a-zA-Z][\\w]*)");