• ,

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

RegEx

Регулярное выражение это своего рода шаблон, который может быть применен к тексту (String, в Java). Java предоставляет пакет java.util.regex для сопоставления с регулярными выражениями. Регулярные выражения очень похожи на язык программирования Perl и очень просты в освоении.
Регулярное выражение или соответствует тексту (его части) или нет.
* Если регулярное выражение совпадает с частю текста, то мы можем найти еe.
** Если регулярное выражение составное, то мы можем легко выяснить, какая часть регулярного выражения совпадает с какой частью текста.

Первый пример
Регулярное выражение "[a-z] +" соответствует всем строчныем буквам в тексте.
[a-z] означает любой символ от a до z включительно, и + означает «один или более» символов.

Предположим, что мы поставляем строку «code 2 learn java tutorial ».

Как это сделать в Java

Во-первых, вы должны составить шаблон:
import java.util.regex.*;
Pattern p = Pattern.compile(“[a-z]+”);

Далее вы должны создать matcher для текста, отправив сообщение на схеме:
Matcher m = p.matcher(“code 2 learn java tutorial”);


ПРИМЕЧАНИЕ:
Ни Pattern ни Matcher не имеют конструкторов, мы создаем их с помощью методов класса Pattern.

Pattern Class: Объект класса составляет представление регулярного выражения. Класс Pattern не предусматривает никаких публичных конструкторов. Чтобы создать шаблон, необходимо сначала вызвать один из публичных статических методов, которые затем возвращают объект класса Pattern. Эти методы принимают регулярное выражение в качестве аргумента.

Matcher Class: Объект «Искатель» является двигателем, который интерпретирует шаблон и выполняет операции сопоставления с входной строкой. Как и Pattern класс, Matcher не имеет публичных конструкторов. Вы получаете объект Matcher вызовом метода matcher, на объекте класса Pattern.

После того как мы выполнили эти шаги, и теперь у нас есть экземпляр класса Matcher m, и теперь мы можем проверить, был найден шаблон или нет, и если да, то в какой позиции, и т.д.

m.matches() возвращает true, если шаблон соответствует всей строке, иначе false.
m.lookingAt() возвращает true, если шаблон соответствует началу строки, и false в противном случае.
m.find () возвращает true, если шаблон совпадает с любой частью текста.

Находим совпадение

После успешного сопостовления, m.start() вернет индекс первого символа, совпавшего и m.end() вернет индекс последнего совпавшего символа, плюс один.

Если была предпринята неудачная попытка и совпадения не нашлось, m.start() и m.end() будут бросать IllegalStateException
— Это RuntimeException, так что вам не придется его ловить.

Может показаться странным, что m.end() возвращает индекс последнего совпавшего символа плюс один, но это именно то, что требуется большинству методов класса String.
— Например, “Now is the time“.substring(m.start(), m.end())
вернет ту же самую строку.

Взглянем на код:


import java.util.regex.*;

public class RegexTest {
    public static void main(String args[]) {
        String pattern = "[a-z]+";
        String text = "code 2 learn java tutorial";
        Pattern p = Pattern.compile(pattern);
        Matcher m = p.matcher(text);
        while(m.find()) {
            System.out.print(text.substring(m.start(), m.end()) + "*");
        }
    }
}

Output: code*learn*java*tutorial*.


Дополнительные методы

Если есть совпадение, то

m.replaceFirst(replacement) возвращает новую строку, где первая подстрока, совпавшая с шаблоном будет заменена на replacement
m.replaceAll(replacement) возвращает новую строку, где каждая подстрока, совпавшая с шаблоном будет заменена
m.find(StartIndex) находи следующее соответствие, начиная с указанного индекса
m.reset() сбрасывает шаблон
m.reset(NewText) сбрасывает искатель, и дает ему новый текст (может быть String, StringBuffer или CharBuffer)

Синтаксис регулярных выражений

^ Соответствует началу строки.
$ Соответствует концу строки.
. Соответствует любому одиночному символу, кроме символа новой строки. Использование опции m позволяет ему соответствовать новой строке.
[...] Соответствует любой одиночный символ в скобках.
[^ ...] Соответствует любому одному символу, не в скобках.
\A Начало всю строку.
\z Конец всей строки.
\Z Конец всей строки, кроме конечного терминатора линии.
re* Соответствует 0 или более вхождений предшествующего выражения.
re+ Одно или более совпадений предыдущего выражения.
re? Соответствует 0 или 1 местонахождению предыдущего выражения.
re{n} Соответствует ровно N Количество вхождений предшествующего выражения.
re{n,} Соответствует N или более вхождений предшествующего выражения.
re{n, m} Матчи по меньшей мере, n и в большинстве m вхождений предшествующего выражения.
a|b Соответствует a или b.
(re) Группа регулярных выражений и помнящая найденный текст.
(?: re) Группы регулярных выражений, не помнящая найденный текст.
(?> re) Соответствует независимому шаблону без возвратов.
\w Соответствует буквам.
\W Соответствует не буквенным символам.
\s Соответствует пробелам. Эквивалентно [\t\n\r\f].
\S Не пробельные символы.
\d Соответствует цифрам. Эквивалентно [0-9].
\D Соответствует не цифрам.
\G Соответствует точки последнего совпадения.
\n Соответствует новой строке.
\b Совпадает на границе слова.
\B Совпадает не на границе слова.
\n, \t, etc. Символы новой строки, возврата каретки, вкладки и т.д.
\Q Цитата все символы до \ E.
\E Заканчивается цитирование начатое с \ Q.

Оригинал перевода
Отличный туториал
Reference — What does this regex mean?
Визуализатор для проверки
Отличный дебаггер с визуализацией

24 комментария

terranum
Надеюсь вам пригодиться, буду благодарен если укажите на ошибки и неточности перевода.
Спасибо и удачи!
isaenkovl
Регулярное выражение либо соответствует с тексту (или его части) или она нет.
Эта строка как-то не читается…
Sant9Iga
Регулярное выражение "[a-z] +" соответствует всем строчные буквы в тексте.
ты гугл переводчиком переводил?)
Sant9Iga
[a-z] означает любой символ от a до z, включая и + означает «один или более».
вот тут не понятно что включая.
timurnav
автору большой плюс к карме, ну и большое спасибо, естественно, а-то все сразу ринулись исправлять)))
Talapius
Рекомендую книгу Джеффри Фридл «Регулярные выражения». Она однозначно стоит потраченного времени! В ней четко описаны некоторые тонкости регулярки, которых нет в документации!
Автору спасибо! Основы регулярки то что нужно!
alexnjc
  • alexnjc
  • +1
  • Комментарий отредактирован 2015-03-01 16:48:32 пользователем alexnjc
Отличный пост, необходимый минимум инфы для быстрого старта с RegExp в одном месте. Спасибо за перевод, побольше бы таких постов.
alexnjc
Из шпаргалок есть такая штука
overapi.com/regex/
А еще есть готовые паттерны для валидации e-mail, телефона, URL адреса сайта и прочих данных.
bulldorez
Люди, подскажите, как составить, к примеру, такую регулярку. Есть строка. Нужно найти в ней слово «blablabla». Слово может быть в начале, в конце, в середине строки. Глупо будет писать:
Pattern p1 = Pattern.compile("^world ");
 p1 = Pattern.compile(" world$");
p1 = Pattern.compile(" world ");


Как это упростить?)
balu1973
  • balu1973
  • 0
  • Комментарий отредактирован 2015-03-07 03:21:13 пользователем balu1973
Pattern.compile("\\bworld\\b");
olegvasylkov
я думаю что следующую ссылку будет полезно сохранить на заметку каждому
darkraha.com/rus/dic/regexp.php
в частности для решения задачек очень полезное выражение \p{Punct}
joyrider
Для тех кто первый раз читает, я бы добавил абзац (пару слов) про экранирующий символ \
werru
в статье ничего нет про модификаторы. А получать ответ в несколько строк без них нельзя
Pattern.CANON_EQ Enables canonical equivalence. When this flag is specified, two characters will be considered to match if, and only if, their full canonical decompositions match. The expression «a\u030A», for example, will match the string "\u00E5" when this flag is specified. By default, matching does not take canonical equivalence into account. Specifying this flag may impose a performance penalty.
Pattern.CASE_INSENSITIVE Enables case-insensitive matching. By default, case-insensitive matching assumes that only characters in the US-ASCII charset are being matched. Unicode-aware case-insensitive matching can be enabled by specifying the UNICODE_CASE flag in conjunction with this flag. Case-insensitive matching can also be enabled via the embedded flag expression (?i). Specifying this flag may impose a slight performance penalty.
Pattern.COMMENTS Permits whitespace and comments in the pattern. In this mode, whitespace is ignored, and embedded comments starting with # are ignored until the end of a line. Comments mode can also be enabled via the embedded flag expression (?x).
Pattern.DOTALL Enables dotall mode. In dotall mode, the expression. matches any character, including a line terminator. By default this expression does not match line terminators. Dotall mode can also be enabled via the embedded flag expression (?s). (The s is a mnemonic for «single-line» mode, which is what this is called in Perl.)
Pattern.LITERAL Enables literal parsing of the pattern. When this flag is specified then the input string that specifies the pattern is treated as a sequence of literal characters. Metacharacters or escape sequences in the input sequence will be given no special meaning. The flags CASE_INSENSITIVE and UNICODE_CASE retain their impact on matching when used in conjunction with this flag. The other flags become superfluous. There is no embedded flag character for enabling literal parsing.
Pattern.MULTILINE Enables multiline mode. In multiline mode the expressions ^ and $ match just after or just before, respectively, a line terminator or the end of the input sequence. By default these expressions only match at the beginning and the end of the entire input sequence. Multiline mode can also be enabled via the embedded flag expression (?m).
Pattern.UNICODE_CASE Enables Unicode-aware case folding. When this flag is specified then case-insensitive matching, when enabled by the CASE_INSENSITIVE flag, is done in a manner consistent with the Unicode Standard. By default, case-insensitive matching assumes that only characters in the US-ASCII charset are being matched. Unicode-aware case folding can also be enabled via the embedded flag expression (?u). Specifying this flag may impose a performance penalty.
Pattern.UNIX_LINES Enables UNIX lines mode. In this mode, only the '\n' line terminator is recognized in the behavior of ., ^, and $. UNIX lines mode can also be enabled via the embedded flag expression (?d).
kototim
  • kototim
  • 0
  • Комментарий отредактирован 2016-08-03 15:48:36 пользователем kototim
Господа, помогите пожалуйста. Пытаюсь написать регулярное выражение так, чтобы вставить после вывода двух строк ещё одну строку.
Пытаюсь создать шаблон таким образом:
result.replaceAll("^$\n^$\n",
                "^$\n" + "^$\n" + "Вставить текст сюда" + "\n");

Похоже я совсем не понимаю принципа. Читаю, читаю, а как-то не откладывается. Надо на конкретных своих примерах разбираться. Ткните пожалуйста носом, как мне написать.
Благодарю.
Написал в итоге вот так, но это какой-то костыль…
String[] textArray = result.split("\n");
        for (int i = 0; i < textArray.length; i++)
        {
            System.out.println(textArray[i]);
            i++;
            if (i > textArray.length-1)
                break;
            System.out.println(textArray[i]);
            System.out.println("Вставить текст сюда");
        }
nshumeik
Переводные статьи могут грешить ошибками. Нужно было составить регулярное выражение «не содержит букв». Судя по этой статье \W как раз то, что надо. Оказывается нет. Смотрим документацию на docs.oracle.com — \w — это буквы и цифры [a-zA-Z_0-9], а \W — это не буквы и не цифры. Автор, поправьте.
pro_moscow
Подскажите, а как пробел на плюс заменить?
vacancy.replaceAll(" ", "+");
не подходит
pro_moscow
Спасибо, разобрался
DedZahar
Помогите разобраться!
хочу найти в строке все отдельно стоящие цифры и вывести их через пробел.
Вот код:
String s = " 12 23 34 45 56 fg fg7 5hj dfkjh 59 ";
        String pattern = "\\s\\d+\\s";
        Pattern p = Pattern.compile(pattern);
        Matcher m = p.matcher(s);
        StringBuilder sb2 = new StringBuilder();
        while (m.find()) {
            String nomber;
            nomber = s.substring(m.start()+1, m.end()-1);
            sb2.append(nomber + " ");
        }
        System.out.println(sb2);

Консоль: «12 34 56 59»
Почему не читаются 23 и 45?
Уже сломал всю голову…
aryumin
Например, вот так:


String s = " 12 23 34 45 56 fg fg7 5hj dfkjh 59 ";
        String pattern = "(?<!\\w)\\d+(?!\\w)";
        Pattern p = Pattern.compile(pattern);
        Matcher m = p.matcher(s);
        StringBuilder sb2 = new StringBuilder();
        while (m.find()) {
            String nomber;
            nomber = s.substring(m.start(), m.end());
            sb2.append(nomber);
            sb2.append(" ");
        }
        System.out.println(sb2);
DedZahar
Но всё-таки, почему не работает "\\s\\d+\\s"?
Объясните, плз.
aryumin
если бы было по два пробела до и после цифр, видимо, сработал бы ваш вариант.
DedZahar
Огромное спасибо! Разобрался!
aryumin
супер )
aryumin
а не читаются они, потому что паттерн захватывает пробел-число-пробел. То есть субстрока заканчивается и начинается на пробелы. find() берет пробелы до и после числа, и следующий find() уже их не видит. Поэтому ваш запрос пропускает часть отдельно стоящих цифр.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.