Регулярные выражения в java, часть 4

Java Regex email example

package com.zetcode;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class JavaRegexEmail {

    public static void main(String[] args) {

        List<String> emails = List.of("luke@gmail.com",
                "andy@yahoocom", "34234sdfa#2345", "f344@gmail.com");

        String regex = "+@+\\.{2,18}";

        Pattern p = Pattern.compile(regex);

        for (String email : emails) {

            Matcher m = p.matcher(email);

            if (m.matches()) {
                System.out.printf("%s matches%n", email);
            } else {
                System.out.printf("%s does not match%n", email);
            }
        }
    }
}

This example provides only one possible solution.

String regex = "+@+\\.{2,18}";

The fourth part is the dot character. It is preceded by the escape character
(\). This is because the dot character is a metacharacter and has a special
meaning. By escaping it, we get a literal dot.

The final part is the top level domain: .
Top level domains can have from 2 to 18 characters, such as sk, net, info,
travel, cleaning, travelinsurance. The maximum length can be 63 characters, but
most domain are shorter than 18 characters today. There is also a dot character.
This is because some top level domains have two parts; for example co.uk.

In this tutorial, we have worked with regular expression in Java.

List .

Замена текста REGEXP_REPLACE

Поиск и замена — одна из лучших областей применения регулярных выражений. Текст замены может включать ссылки на части исходного выражения (называемые обратными ссылками), открывающие чрезвычайно мощные возможности при работе с текстом. Допустим, имеется список имен, разделенный запятыми, и его содержимое необходимо вывести по два имени в строке. Одно из решений заключается в том, чтобы заменить каждую вторую запятую символом новой строки. Сделать это при помощи стандартной функции нелегко, но с функцией задача решается просто. Общий синтаксис ее вызова: 

REGEXP_REPLACE (исходная_строка, шаблон ]])

Здесь исходная_строка — строка, в которой выполняется поиск; шаблон — регулярное выражение, совпадение которого ищется в исходной_строке; начальная_позиция — позиция, с которой начинается поиск; модификаторы — один или несколько модификаторов, управляющих процессом поиска. Пример:

DECLARE
names VARCHAR2(60) := 'Anna,Matt,Joe,Nathan,Andrew,Jeff,Aaron';
names_adjusted VARCHAR2(61);
comma_delimited BOOLEAN;
extracted_name VARCHAR2(60);
name_counter NUMBER;
BEGIN
-- Искать совпадение шаблона
comma_delimited := REGEXP_LIKE(names,'^(*,)+(*){1}$', 'i');
-- Продолжать, только если мы действительно
-- работаем со списком, разделенным запятыми.
IF comma_delimited THEN
names := REGEXP_REPLACE(
names,
'(*),(*),',
'\1,\2' || chr(10) );
END IF;
DBMS_OUTPUT.PUT_LINE(names);
END;

Результат выглядит так:

Anna,Matt
Joe,Nathan
Andrew,Jeff
Aaron  

При вызове функции передаются три аргумента:

  • names — исходная строка;
  • ‘(*),(*),’ — выражение, описывающее заменяемый текст (см. ниже);
  • ‘\1,\2 ‘ || chr(10) — текст замены. \1 и \2 — обратные ссылки, заложенные в основу нашего решения. Подробные объяснения также приводятся ниже.

Выражение, описывающее искомый текст, состоит из двух подвыражений в круглых скобках и двух запятых.

  • Совпадение должно начинаться с имени.
  • За именем должна следовать запятая.
  • Затем идет другое имя.
  • И снова одна запятая.

Наша цель — заменить каждую вторую запятую символом новой строки. Вот почему выражение написано так, чтобы оно совпадало с двумя именами и двумя запятыми. Также запятые не напрасно выведены за пределы подвыражений.

Первое совпадение для нашего выражения, которое будет найдено при вызове , выглядит так: 

Anna,Matt,

Два подвыражения соответствуют именам «» и «». В основе нашего решения лежит возможность ссылаться на текст, совпавший с заданным подвыражением, через обратную ссылку. Обратные ссылки и в тексте замены ссылаются на текст, совпавший с первым и вторым подвыражением. Вот что происходит: 

'\1,\2' || chr(10)     -- Текст замены
'Anna,\2' || chr(10)   -- Подстановка текста, совпавшего
                       -- с первым подвыражением
'Anna,Matt' || chr(10) -- Подстановка текста, совпавшего
                       -- со вторым подвыражением

Вероятно, вы уже видите, какие мощные инструменты оказались в вашем распоряжении. Запятые из исходного текста попросту не используются. Мы берем текст, совпавший с двумя подвыражениями (имена «Anna» и «Matt»), и вставляем их в новую строку с одной запятой и одним символом новой строки.

Но и это еще не все! Текст замены легко изменить так, чтобы вместо запятой в нем использовался символ табуляции (ASCII-код 9): 

names := REGEXP_REPLACE(
names,
'(*),(*),',
'\1' || chr(9) || '\2' || chr(10) );

Теперь результаты выводятся в два аккуратных столбца:

Anna Matt
Joe Nathan
Andrew Jeff
Aaron 

Поиск и замена с использованием регулярных выражений — замечательная штука. Это мощный и элегантный механизм, с помощью которого можно сделать очень многое.

Жадный режим квантификатора

Сверхжадный режим

мы получим такой вывод:

Алла Алекса

  1. В заданном шаблоне первый символ – это русский символ буквы . сопоставляет его с каждым символом текста, начиная с нулевой позиции. На нулевой позиции в нашем тексте находиться символ , поэтому перебирает последовательно символы в тексте, пока не встретит совпадение с шаблоном. В нашем примере это символ на позиции №5.

  2. После того, как найдено совпадение с первым символом шаблона, сверяет соответствие со вторым символом шаблона. В нашем случае это символ «», который обозначает любой символ.

    На шестой позиции – символ буквы . Разумеется, он соответствует шаблону «любой символ».

  3. переходит к проверке следующего символа из шаблона. В нашем шаблоне он задан с помощью квантификатора «». Поскольку количество повторений «любого символа» в шаблоне – один и более раз, берет по очереди следующий символ из строки и проверяет его на соответствие шаблону, до тех пор, пока будет выполняться условие «любой символ», в нашем примере – до конца строки (с поз. №7 -№18 текста).

    По сути, , захватывает все строку до конца – в этом как раз и проявляется его «жадность».

  4. После того как дошел до конца текста и закончил проверку для части шаблона «», Matcher начинает проверку для оставшейся части шаблона – символ буквы . Так как текст в прямом направлении закончился, проверка происходит в обратном направлении, начиная с последнего символа:

  5. «помнит» количество повторений в шаблоне «» при котором он дошел до конца текста, поэтому он уменьшает количество повторений на единицу и проверяет соответствие шаблона тексту, до тех пор пока не будет найдено совпадение:

Методы appendReplace и appendTail

Класс Matcher также предоставляет методы appendReplacement и appendTail для замены текста.

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexMatches {

   private static String REGEX = "a*b";
   private static String INPUT = "aabfooaabfooabfoob";
   private static String REPLACE = "-";
   public static void main(String[] args) {

      Pattern p = Pattern.compile(REGEX);
      
      Matcher m = p.matcher(INPUT);
      StringBuffer sb = new StringBuffer();
      while(m.find()) {
         m.appendReplacement(sb, REPLACE);
      }
      m.appendTail(sb);
      System.out.println(sb.toString());
   }
}

Вывод:

appendReplacement методы и appendTail

Класс Сличитель также обеспечивает способ appendTail appendReplacement и заменить текст:

Посмотрите на следующий пример, чтобы объяснить эту особенность:

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexMatches
{
   private static String REGEX = "a*b";
   private static String INPUT = "aabfooaabfooabfoob";
   private static String REPLACE = "-";
   public static void main(String[] args) {
      Pattern p = Pattern.compile(REGEX);
      // 获取 matcher 对象
      Matcher m = p.matcher(INPUT);
      StringBuffer sb = new StringBuffer();
      while(m.find()){
         m.appendReplacement(sb,REPLACE);
      }
      m.appendTail(sb);
      System.out.println(sb.toString());
   }
}

Приведенные выше примеры скомпилированные получены следующие результаты:

-foo-foo-foo-

Проверка наличия совпадения

Регулярные выражения используются для описания текста, который требуется найти в строке (и возможно, подвергнуть дополнительной обработке). Давайте вернемся к примеру, который приводился ранее в этом блоге:

DECLARE
names VARCHAR2(60) := 'Anna,Matt,Joe,Nathan,Andrew,Aaron,Jeff';

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

DECLARE
names VARCHAR2(60) := 'Anna,Matt,Joe,Nathan,Andrew,Jeff,Aaron';
names_adjusted VARCHAR2(61);
comma_delimited BOOLEAN;
BEGIN
--Поиск по шаблону
comma_delimited := REGEXP_LIKE(names,'^(*,)+(*){1}$');
--Вывод результата
DBMS_OUTPUT.PUT_LINE(
CASE comma_delimited
WHEN true THEN 'Обнаружен список с разделителями!'
ELSE 'Совпадение отсутствует.'
END);
END;

Результат:

Обнаружен список с разделителями 

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

REGEXP_LIKE (исходная_строка, шаблон ) 

Здесь — символьная строка, в которой ищутся совпадения; шаблон — регулярное выражение, совпадения которого ищутся в исходной_строке; модификаторы — один или несколько модификаторов, управляющих процессом поиска. Если функция находит совпадение шаблона в , она возвращает логическое значение ; в противном случае возвращается .

Процесс построения регулярного выражения выглядел примерно так:

  • Каждый элемент списка имен может состоять только из букв и пробелов. Квадратные скобки определяют набор символов, которые могут входить в совпадение. Диапазон a–z описывает все буквы нижнего регистра, а диапазон A–Z — все буквы верхнего регистра. Пробел находится между двумя компонентами выражения. Таким образом, этот шаблон описывает один любой символ нижнего или верхнего регистра или пробел.
  • * Звездочка является квантификатором — служебным символом, который указывает, что каждый элемент списка содержит ноль или более повторений совпадения, описанного шаблоном в квадратных скобках.
  • *, Каждый элемент списка должен завершаться запятой. Последний элемент является исключением, но пока мы не будем обращать внимания на эту подробность.
  • *,) Круглые скобки определяют подвыражение, которое описывает некоторое количество символов, завершаемых запятой. Мы определяем это подвыражение, потому что оно должно повторяться при поиске.
  • ]*,)+ Знак + — еще один квантификатор, применяемый к предшествующему элементу (то есть к подвыражению в круглых скобках). В отличие от * знак + означает «одно или более повторений». Список, разделенный запятыми, состоит из одного или нескольких повторений подвыражения.
  • ( В шаблон добавляется еще одно подвыражение: (*). Оно почти совпадает с первым, но не содержит запятой. Последний элемент списка не завершается запятой.
  • Мы добавляем квантификатор {1}, чтобы разрешить вхождение ровно одного элемента списка без завершающей запятой.
  • ^ Наконец, метасимволы ^ и привязывают потенциальное совпадение к началу и концу целевой строки. Это означает, что совпадением шаблона может быть только вся строка вместо некоторого подмножества ее символов.

Функция анализирует список имен и проверяет, соответствует ли он шаблону. Эта функция оптимизирована для простого обнаружения совпадения шаблона в строке, но другие функции способны на большее!

Пример валидации e-mail адреса

Регулярные выражения могут быть очень полезны при server- и client-side валидации данных.

import java.util.regex.*;

public class TestRegexp {
    public static final Pattern pattern = Pattern.compile
        ("{1}+@(+\\u002E){1,2}((net)|(com)|(org))");

    public static void doMatch(String word) {
        Matcher matcher = pattern.matcher(word);
        System.out.println("Validation for " + word +
                (matcher.matches() ? " passed." : "not passed."));
    }

    public static void main(String[] args) {
        doMatch("c0nst@money.simply.net");
        doMatch("Name.Sur_name@gmail.com");
        doMatch("useR33@somewhere.in.the.net");
    }
}

Последовательность вида указывает на множество, в нашем случае это множество латинских символов в верхнем и нижнем регистрах.
{n} говорит о том, что некоторый символ должен встретится n раз, а {n,m} — от n до m раз.
Символ \d указывает на множество цифр. «\u002E» и «\u005F» — это символы точки и подчеркивания соответсвенно.
Знак плюс после некоторой последовательности говорит о том, что она должна встретится один или более раз.
«|» — представление логического «или».

Полное описание всех конструкций можно найти в Java API.

А вот и результат выполнения программы:

Validation for c0nst@money.simply.net passed.
Validation for Name.Sur_name@gmail.com passed.
Validation for user33@somewhere.in.the.net not passed.

Естественно в интернете можно найти намного более сложные регулярки для проверки почтового адреса. Главное, чтобы была понятна идея.

Character Classes

Character classes may appear within other character classes, and
may be composed by the union operator (implicit) and the intersection
operator ().
The union operator denotes a class that contains every character that is
in at least one of its operand classes. The intersection operator
denotes a class that contains every character that is in both of its
operand classes.

The precedence of character-class operators is as follows, from
highest to lowest:

Precedence Name Example
1 Literal escape    
2 Grouping
3 Range
4 Union
5 Intersection

Note that a different set of metacharacters are in effect inside
a character class than outside a character class. For instance, the
regular expression loses its special meaning inside a
character class, while the expression becomes a range
forming metacharacter.

Методы replaceFirst и replaceAll

Методы replaceFirst и replaceAll заменяют текст, соответствующий заданному регулярному выражению. replaceFirst заменяет первое вхождение, а replaceAll заменяет все вхождения.

Вот пример, объясняющий их работу:

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexMatches {

   private static String REGEX = "dog";
   private static String INPUT = "The dog says meow. " + "All dogs say meow.";
   private static String REPLACE = "cat";

   public static void main(String[] args) {
      Pattern p = Pattern.compile(REGEX);
      
      // получаем объект соответствия
      Matcher m = p.matcher(INPUT); 
      INPUT = m.replaceAll(REPLACE);
      System.out.println(INPUT);
   }
}

И теперь вывод:

Meta Characters

Meta characters affect the way a pattern is matched, in a way adding logic to the search pattern. The Java API supports several metacharacters, the most straightforward being the dot “.” which matches any character:

Considering the previous example where regex foo matched the text foo as well as foofoo two times. If we used the dot metacharacter in the regex, we would not get two matches in the second case:

Notice the dot after the foo in the regex. The matcher matches every text that is preceded by foo since the last dot part means any character after. So after finding the first foo, the rest is seen as any character. That is why there is only a single match.

The API supports several other meta characters <(})?*+.> which we will be looking into further in this article.

Capturing Groups

The API also allows us to treat multiple characters as a single unit through capturing groups.

It will attache numbers to the capturing groups and allow back referencing using these numbers.

In this section, we will see a few examples on how to use capturing groups in Java regex API.

Let’s use a capturing group that matches only when an input text contains two digits next to each other:

The number attached to the above match is 1, using a back reference to tell the matcher that we want to match another occurrence of the matched portion of the text. This way, instead of:

Where there are two separate matches for the input, we can have one match but propagating the same regex match to span the entire length of the input using back referencing:

Where we would have to repeat the regex without back referencing to achieve the same result:

Similarly, for any other number of repetitions, back referencing can make the matcher see the input as a single match:

But if you change even the last digit, the match will fail:

It is important not to forget the escape backslashes, this is crucial in Java syntax.

Часто используемые регулярные выражения

Регулярные выражения широко используются в Интернете. Регулярные выражения практически неотделимы от современных вычислительных приложений, от проверки форм до поиска данных, содержащих определенное ключевое слово или ключевые слова.

Давайте посмотрим на несколько знакомых примеров использования регулярных выражений.

Соответствие номера телефона

Давайте посмотрим, каков образец телефонного номера, используемого например в Индии. Код страны идет первым. Обычно он содержит символ «+», за которым следует число 91, которое является кодом страны для Индии. Кроме того, номера телефонов в Индии обычно начинаются с 6, 7, 8 или 9. За ними следуют еще 9 цифр.

Таким образом, действительное регулярное выражение для индийского номера мобильного телефона будет таким:

Проверка надежности паролей

Большинство веб-сайтов рекомендуют нам предоставить надежный пароль, который содержит комбинацию цифр, прописных и строчных букв и символов. Также должно быть минимальное количество символов — 6 или 8. Это сделано для того, чтобы пароль было очень сложно взломать.

Любой пароль, соответствующий этому правилу, может быть сгенерирован или подтвержден на надежность пароля с помощью регулярного выражения.

Соответствие URL

URL-адреса — это наиболее распространенный способ использования Интернета и быстрого перехода на нужную веб-страницу. Почти у каждого веб-сайта есть URL-адрес. Следовательно, каждый URL-адрес стандартизирован и следует определенному шаблону. Каждый URL следует либо по протоколу HTTP, либо по протоколу HTTP, за которым часто следует « : // » и « www ». Затем название веб-сайта, за которым следует .com, .ru, .net, .org и т. д.

Чтобы проверить правильность URL-адреса, мы можем использовать регулярное выражение, подобное приведенному ниже.

Форматы даты и времени

Форматы даты и времени также очень часто используются в Интернете. Есть много форматов дат, используемых в различных приложениях, программном обеспечении или системах. Даты всегда следует использовать в формате, позволяющем использовать их для пользователя или приложения, которое пытается их прочитать.

Дата в формате дд-ММ-гггг может быть проверена с помощью регулярного выражения, которое может быть таким, как указано ниже.

Также рекомендуем прочитать:

  1. Самые полезные расширения VS Code для повышения производительности
  2. Как добавить темную тему на свой сайт с помощью CSS и JavaScript
  3. 10 лучших шрифтов для программирования, которые нужны разработчикам
  4. 8 шагов, как получить 100 звезд и больше на GitHub

Pattern.matcher()

Как только получили экземпляр Pattern, можете использовать его для получения экземпляра Matcher. Он используется для поиска совпадений шаблона в текстах:

Matcher matcher = pattern.matcher(text);

Класс Matcher имеет метод matcher(), который проверяет, соответствует ли шаблон тексту:

import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class PatternMatcherExample {

    public static void main(String[] args) {

        String text    =
            "This is the text to be searched " +
            "for occurrences of the http:// pattern.";

        String patternString = ".*http://.*";

        Pattern pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE);

        Matcher matcher = pattern.matcher(text);

        boolean matches = matcher.matches();

        System.out.println("matches = " + matches);
    }
}

Matcher очень продвинутый и позволяет вам получить доступ к соответствующим частям текста различными способами.

Comparison to Perl 5

The engine performs traditional NFA-based matching
with ordered alternation as occurs in Perl 5.

Perl constructs not supported by this class:

  • The backreference constructs, n for
    the nth and
    name for
    .

  • The conditional constructs
    conditionX and
    conditionXY,

  • The embedded code constructs code
    and code,

  • The embedded comment syntax , and

  • The preprocessing operations ,
    , and .

Constructs supported by this class but not by Perl:

Character-class union and intersection as described
above.

Notable differences from Perl:

  • In Perl, through are always interpreted
    as back references; a backslash-escaped number greater than is
    treated as a back reference if at least that many subexpressions exist,
    otherwise it is interpreted, if possible, as an octal escape. In this
    class octal escapes must always begin with a zero. In this class,
    through are always interpreted as back
    references, and a larger number is accepted as a back reference if at
    least that many subexpressions exist at that point in the regular
    expression, otherwise the parser will drop digits until the number is
    smaller or equal to the existing number of groups or it is one digit.

  • Perl uses the flag to request a match that resumes
    where the last match left off. This functionality is provided implicitly
    by the class: Repeated invocations of the method will resume where the last match left off,
    unless the matcher is reset.

  • In Perl, embedded flags at the top level of an expression affect
    the whole expression. In this class, embedded flags always take effect
    at the point at which they appear, whether they are at the top level or
    within a group; in the latter case, flags are restored at the end of the
    group just as in Perl.

Line terminators

A line terminator is a one- or two-character sequence that marks
the end of a line of the input character sequence. The following are
recognized as line terminators:

  • A newline (line feed) character (),

  • A carriage-return character followed immediately by a newline
    character (),

  • A standalone carriage-return character (),

  • A next-line character (),

  • A line-separator character (), or

  • A paragraph-separator character ().

If mode is activated, then the only line terminators
recognized are newline characters.

The regular expression matches any character except a line
terminator unless the flag is specified.

By default, the regular expressions and ignore
line terminators and only match at the beginning and the end, respectively,
of the entire input sequence. If mode is activated then
matches at the beginning of input and after any line terminator
except at the end of input. When in mode
matches just before a line terminator or the end of the input sequence.

replaceFirst методы и replaceAll

replaceFirst и replaceAll метод, используемый для замены регулярного выражения соответствия текста. Разница, replaceFirst заменить первый матч, replaceAll заменить все матчи.

Следующий пример, чтобы объяснить эту особенность:

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexMatches
{
    private static String REGEX = "dog";
    private static String INPUT = "The dog says meow. " +
                                    "All dogs say meow.";
    private static String REPLACE = "cat";

    public static void main(String[] args) {
       Pattern p = Pattern.compile(REGEX);
       // get a matcher object
       Matcher m = p.matcher(INPUT); 
       INPUT = m.replaceAll(REPLACE);
       System.out.println(INPUT);
   }
}

Приведенные выше примеры скомпилированные получены следующие результаты:

The cat says meow. All cats say meow.

Matcher Class Methods

In this section, we will look at some useful methods of the Matcher class. We will group them according to functionality for clarity.

12.1. Index Methods

Index methods provide useful index values that show precisely where the match was found in the input String . In the following test, we will confirm the start and end indices of the match for dog in the input String :

12.2. Study Methods

Study methods go through the input String and return a boolean indicating whether or not the pattern is found. Commonly used are matches and lookingAt methods.

The matches and lookingAt methods both attempt to match an input sequence against a pattern. The difference, is that matches requires the entire input sequence to be matched, while lookingAt does not.

Both methods start at the beginning of the input String :

The matches method will return true in a case like so:

12.3. Replacement Methods

Replacement methods are useful to replace text in an input string. The common ones are replaceFirst and replaceAll.

The replaceFirst and replaceAll methods replace the text that matches a given regular expression. As their names indicate, replaceFirst replaces the first occurrence, and replaceAll replaces all occurrences:

Replace all occurrences:

The replaceAll method allows us to substitute all matches with the same replacement. If we want to replace matches on a case by basis, we’d need a token replacement technique.

Backslashes, escapes, and quoting

The backslash character () serves to introduce escaped
constructs, as defined in the table above, as well as to quote characters
that otherwise would be interpreted as unescaped constructs. Thus the
expression matches a single backslash and matches a
left brace.

It is an error to use a backslash prior to any alphabetic character that
does not denote an escaped construct; these are reserved for future
extensions to the regular-expression language. A backslash may be used
prior to a non-alphabetic character regardless of whether that character is
part of an unescaped construct.

Backslashes within string literals in Java source code are interpreted
as required by
The Java Language Specification
as either Unicode escapes (section 3.3) or other character escapes (section 3.10.6)
It is therefore necessary to double backslashes in string
literals that represent regular expressions to protect them from
interpretation by the Java bytecode compiler. The string literal
, for example, matches a single backspace character when
interpreted as a regular expression, while matches a
word boundary. The string literal is illegal
and leads to a compile-time error; in order to match the string
the string literal
must be used.

Методы поиска(lookingAt)

Методы match и LookingAt пытаются сопоставить входную последовательность с шаблоном. Разница, однако, заключается в том, что для matches требуется сопоставление всей входной последовательности, а для lookingAt — нет.

Оба метода всегда начинаются с начала строки ввода. Вот пример:

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexMatches {

   private static final String REGEX = "foo";
   private static final String INPUT = "fooooooooooooooooo";
   private static Pattern pattern;
   private static Matcher matcher;

   public static void main( String args[] ) {
      pattern = Pattern.compile(REGEX);
      matcher = pattern.matcher(INPUT);

      System.out.println("Current REGEX is: "+REGEX);
      System.out.println("Current INPUT is: "+INPUT);

      System.out.println("lookingAt(): "+matcher.lookingAt());
      System.out.println("matches(): "+matcher.matches());
   }
}

Получим следующий результат:

Методы Study

Методы Study проверяют входную строку и возвращают логическое значение, указывающее, найден ли шаблон.

Метод и описание
1 public boolean lookingAt() Пытается сопоставить входную последовательность, начиная с начала, с шаблоном.
2 public boolean find() Пытается найти следующую подпоследовательность входной последовательности, которая соответствует шаблону.
3 public boolean find(int start) Сбрасывает это сопоставление и затем пытается найти следующую подпоследовательность входной последовательности, которая соответствует шаблону, начиная с указанного индекса.
4 public boolean matches() Попытки сопоставить весь регион с паттерном.

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

Последнее обновление: 1.11.2015

Рассмотрим базовые моменты синтаксиса регулярных выражений.

Метасимволы

Регулярные выражения также могут использовать метасимволы — символы, которые имеют определенный смысл:

  • : соответствует любой цифре от 0 до 9

  • : соответствует любому символу, который не является цифрой

  • : соответствует любой букве, цифре или символу подчеркивания (диапазоны A–Z, a–z, 0–9)

  • : соответствует любому символу, который не является буквой, цифрой или символом подчеркивания (то есть не находится в следующих диапазонах A–Z, a–z, 0–9)

  • : соответствует пробелу

  • : соответствует любому символу, который не является пробелом

  • : соответствует любому символу

Здесь надо заметить, что метасимвол \w применяется только для букв латинского алфавита, кириллические символы для него не подходят.

Так, стандартный формат номера телефона соответствует регулярному выражению .

Например, заменим числа номера нулями:

var phoneNumber = «+1-234-567-8901»; var myExp = /\d-\d\d\d-\d\d\d-\d\d\d\d/; phoneNumber = phoneNumber.replace(myExp, «00000000000»); document.write(phoneNumber);

Модификаторы

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

  • : соответствует n-ому количеству повторений предыдущего символа. Например, соответствует подстроке «hhh»

  • : соответствует n и более количеству повторений предыдущего символа. Например, соответствует подстрокам «hhh», «hhhh», «hhhhh» и т.д.

  • : соответствует от n до m повторений предыдущего символа. Например, соответствует подстрокам «hh», «hhh», «hhhh».

  • : соответствует одному вхождению предыдущего символа в подстроку или его отсутствию в подстроке. Например, соответствует подстрокам «home» и «ome».

  • : соответствует одному и более повторений предыдущего символа

  • : соответствует любому количеству повторений или отсутствию предыдущего символа

  • : соответствует началу строки.

    Например, соответствует строке «home», но не «ohma», так как h должен представлять начало строки

  • : соответствует концу строки. Например, соответствует строке «дом», так как строка должна оканчиваться на букву м

Например, возьмем номер тот же телефона. Ему соответствует регулярное выражение . Однако с помощью выше рассмотренных комбинаций мы его можем упростить:

Также надо отметить, что так как символы ?, +, * имеют особый смысл в регулярных выражениях, то чтобы их использовать в обычным для них значении (например, нам надо заменить знак плюс в строке на минус), то данные символы надо экранировать с помощью слеша:

var phoneNumber = «+1-234-567-8901»; var myExp = /\+\d-\d{3}-\d{3}-\d{4}/; phoneNumber = phoneNumber.replace(myExp, «80000000000»); document.write(phoneNumber);

Отдельно рассмотрим применение комбинации ‘\b’, которая указывает на соответствие в пределах слова. Например, у нас есть следующая строка: «Языки обучения: Java, JavaScript, C++». Со временем мы решили, что Java надо заменить на C#. Но простая замена приведет также к замене строки «JavaScript» на «C#Script», что недопустимо. И в этом случае мы можем проводить замену, если регуляное выражение соответствует всему слову:

var initialText = «Языки обучения: Java, JavaScript, C++»; var exp = /Java\b/g; var result = initialText.replace(exp, «C#»); document.write(result); // Языки обучения: C#, JavaScript, C++

Но при использовании ‘\b’ надо учитывать, что в JavaScript отсутствует полноценная поддержка юникода, поэтому применять ‘\b’ мы сможем только к англоязычным словам.

Использование групп в регулярных выражениях

Для поиска в строке более сложных соответствий применяются группы. В регулярных выражениях группы заключаются в скобки. Например, у нас есть следующий код html, который содержит тег изображения: ‘<img src=»https://steptosleep.ru/wp-content/uploads/2018/06/47616.png» />’. И допустим, нам надо вычленить из этого кода пути к изображениям:

var initialText = ‘<img src= «picture.png» />’; var exp = /+\.(png|jpg)/i; var result = initialText.match(exp); result.forEach(function(value, index, array){ document.write(value + «<br/>»); })

Вывод браузера:

picture.png png

Первая часть до скобок (+\.) указывает на наличие в строке от 1 и более символов из диапазона a-z, после которых идет точка. Так как точка является специальным символом в регулярных выражениях, то она экранируется слешем. А дальше идет группа: . Эта группа указывает, что после точки может использоваться как «png», так и «jpg».

Java Regex capturing groups

Round brackets are used to create capturing groups. This allows
us to apply a quantifier to the entire group or to restrict alternation to a
part of the regular expression.

com/zetcode/JavaRegexGroups.java

package com.zetcode;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class JavaRegexGroups {

    public static void main(String[] args) {

        var sites = List.of("webcode.me", "zetcode.com", "freebsd.org", 
            "netbsd.org");

        Pattern p = Pattern.compile("(\\w+)\\.(\\w+)");

        for (var site: sites) {

            Matcher matcher = p.matcher(site);

            while (matcher.find()) {

                System.out.println(matcher.group(0));
                System.out.println(matcher.group(1));
                System.out.println(matcher.group(2));
            }
            
            System.out.println("*****************");
        }
    }
}

In the example, we divide the domain names into two parts by using groups.

Pattern p = Pattern.compile("(\\w+)\\.(\\w+)");

We define two groups with parentheses.

while (matcher.find()) {

    System.out.println(matcher.group(0));
    System.out.println(matcher.group(1));
    System.out.println(matcher.group(2));
}

The groups are accessed via the method.
The returns the whole matched string.

webcode.me
webcode
me
*****************
zetcode.com
zetcode
com
*****************
freebsd.org
freebsd
org
*****************
netbsd.org
netbsd
org
*****************

This is the output.

In the following example, we use groups to work with expressions.

com/zetcode/JavaRegexExpressions.java

package com.zetcode;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class JavaRegexExpressions {

    public static void main(String[] args) {

        String[] expressions = {"16 + 11", "12 * 5", "27 / 3", "2 - 8"};
        String pattern = "(\\d+)\\s+()\\s+(\\d+)";

        for (var expression : expressions) {

            Pattern p = Pattern.compile(pattern);
            Matcher matcher = p.matcher(expression);

            while (matcher.find()) {

                int val1 = Integer.parseInt(matcher.group(1));
                int val2 = Integer.parseInt(matcher.group(3));
                String oper = matcher.group(2);

                var result = switch (oper) {

                    case "+" -> String.format("%s = %d", expression, val1 + val2);
                    case "-" -> String.format("%s = %d", expression, val1 - val2);
                    case "*" -> String.format("%s = %d", expression, val1 * val2);
                    case "/" -> String.format("%s = %d", expression, val1 / val2);
                    default -> "Unknown operator";
                };

                System.out.println(result);
            }
        }
    }
}

The example parses four simple mathematical expressions and computes them.

String[] expressions = {"16 + 11", "12 * 5", "27 / 3", "2 - 8"};

We have an array of four expressions.

String pattern = "(\\d+)\\s+()\\s+(\\d+)";

In the regex pattern, we have three groups: two groups for the values, one for
the operator.

int val1 = Integer.parseInt(matcher.group(1));
int val2 = Integer.parseInt(matcher.group(3));

We get the values and transform them into integers.

String oper = matcher.group(2);

We get the operator.

var result = switch (oper) {

    case "+" -> String.format("%s = %d", expression, val1 + val2);
    case "-" -> String.format("%s = %d", expression, val1 - val2);
    case "*" -> String.format("%s = %d", expression, val1 * val2);
    case "/" -> String.format("%s = %d", expression, val1 / val2);
    default -> "Unknown operator";
};

With the switch expression, we compute the expressions.

16 + 11 = 27
12 * 5 = 60
27 / 3 = 9
2 - 8 = -6

This is the output.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector