JavaRush /Java блог /Random UA /Регулярні вирази в Java, частина 4
Professor Hans Noodles
41 рівень

Регулярні вирази в Java, частина 4

Стаття з групи Random UA
Пропонуємо до вашої уваги переклад короткого посібника з регулярних виразів у мові Java, написаного Джеффом Фрісеном (Jeff Friesen) для сайту javaworld . Для простоти читання ми розділабо статтю кілька частин. Регулярні вирази Java, частина 4 - 1 Регулярні вирази в Java, частина 1 Регулярні вирази в Java, частина 2 Регулярні вирази в Java, частина 3

Методи роботи з захоплюваними групами

Вихідний код програми RegexDemoвключає виклик методу m.group(). Метод group()– одне із кількох методів класу Matcher, орієнтованих працювати із захоплюваними групами:
  • Метод int groupCount()повертає кількість груп, що захоплюються в шаблоні співставника. Ця кількість не враховує спеціальну групу, що захоплюється, номер 0, відповідну шаблону в цілому.

  • Метод String group()повертає символи попереднього знайденого збігу. Щоб повідомити про успішний пошук по порожньому рядку, цей метод повертає порожній рядок. Якщо порівняч ще не виконував пошуку або попередня операція пошуку завершилася невдачею, генерується виняток IllegalStateException.

  • Метод String group(int group)нагадує попередній метод, за винятком того, що повертає символи попереднього знайденого збігу, захоплені групою, номер якої задається параметром group. Зверніть увагу, що group(0)еквівалентно group(). Якщо в шаблоні немає групи з заданим номером, метод генерує виняток IndexOutOfBoundsException. Якщо порівняч ще не виконував пошуку або попередня операція пошуку завершилася невдачею, генерується виняток IllegalStateException.

  • Метод String group(String name)повертає символи попереднього знайденого збігу, захоплені групою name. Якщо групи name у шаблоні немає, генерується виняток IllegalArgumentException. Якщо порівняч ще не виконував пошуку або попередня операція пошуку завершилася невдачею, генерується виняток IllegalStateException.

Наступний приклад демонструє використання методів groupCount()та group(int group):
Pattern p = Pattern.compile("(.(.(.)))");
Matcher m = p.matcher("abc");
m.find();
System.out.println(m.groupCount());
for (int i = 0; i <= m.groupCount(); i++)
System.out.println(i + ": " + m.group(i));
Результати виконання:
3
0: abc
1: abc
2: bc
3: c
Регулярні вирази у Java, частина 4 - 2

Методи визначення позицій збігів

Клас Matcherнадає кілька методів, що повертають початкову та кінцеву позиції збігу:
  • Метод int start()повертає початкову позицію попереднього знайденого збігу. Якщо порівняч ще не виконував пошуку або попередня операція пошуку завершилася невдачею, генерується виняток IllegalStateException.

  • Метод int start(int group)нагадує попередній метод, але повертає початкову позицію попереднього знайденого збігу групи, номер якої задається параметром group. Якщо в шаблоні немає групи з заданим номером, метод генерує виняток IndexOutOfBoundsException. Якщо порівняч ще не виконував пошуку або попередня операція пошуку завершилася невдачею, генерується виняток IllegalStateException.

  • Метод int start(String name)нагадує попередній метод, але повертає початкову позицію попереднього знайденого збігу групи з назвою name. Якщо групи, що захоплюється, nameу шаблоні немає, генерується виняток IllegalArgumentException. Якщо порівняч ще не виконував пошуку або попередня операція пошуку завершилася невдачею, генерується виняток IllegalStateException.

  • Метод int end()повертає позицію останнього із символів попереднього знайденого збігу плюс 1. Якщо співставник ще не виконував пошуку або попередня операція пошуку завершилася невдачею, генерується виняток IllegalStateException.

  • Метод int end(int group)нагадує попередній метод, але повертає кінцеву позицію попереднього знайденого збігу групи, номер якої задається параметром group. Якщо в шаблоні немає групи з заданим номером, метод генерує виняток IndexOutOfBoundsException. Якщо порівняч ще не виконував пошуку або попередня операція пошуку завершилася невдачею, генерується виняток IllegalStateException.

  • Метод int end(String name)нагадує попередній метод, але повертає кінцеву позицію попереднього знайденого збігу групи з назвою name. Якщо групи, що захоплюється, nameу шаблоні немає, генерується виняток IllegalArgumentException. Якщо порівняч ще не виконував пошуку або попередня операція пошуку завершилася невдачею, генерується виняток IllegalStateException.

Наступний приклад демонструє два методи позиціонування збігів, що виводять початкову/кінцеву позиції збігу для захоплюваної групи номер 2:
Pattern p = Pattern.compile("(.(.(.)))");
Matcher m = p.matcher("abcabcabc");
while (m.find())
{
   System.out.println("Найдено " + m.group(2));
   System.out.println("  начинается с позиции " + m.start(2) +
                      " и заканчивается на позиции " + (m.end(2) - 1));
   System.out.println();
}
В результаті виконання цього прикладу виводиться таке:
Найдено bc
начинается с позиции 1 и заканчивается на позиции 2
Найдено bc
начинается с позиции 4 и заканчивается на позиции 5
Найдено bc
начинается с позиции 7 и заканчивается на позиции 8

Методи класу PatternSyntaxException

Примірник класу PatternSyntaxExceptionописує синтаксичну помилку у регулярному вираженні. Генерує такий виняток з методів compile()і matches()класу Pattern, а формується за допомогою наступного конструктора: PatternSyntaxException(String desc, String regex, int index) Цей конструктор зберігає вказаний опис ( desc), регулярний вираз ( regex) та позицію, на якій відбулася синтаксична помилка. Якщо місце синтаксичної помилки невідоме, значення indexвстановлюється рівним -1. Швидше за все, вам ніколи не знадобиться створювати екземпляри класу PatternSyntaxException. Тим не менш, потрібно буде виймати вищезазначені значення при створенні форматованого повідомлення про помилку. Для цього можна скористатися такими методами:
  • Метод String getDescription()повертає опис синтаксичної помилки.
  • Метод int getIndex()повертає або позицію, де сталася помилка, або -1, якщо позиція невідома.
  • Метод String getPattern()повертає помилкове регулярне вираження.
Крім того, успадкований метод String getMessage()повертає багаторядковий рядок зі значеннями, повернутими з попередніх методів разом із візуальною вказівкою на місце синтаксичної помилки у шаблоні. Що таке синтаксична помилка? Ось приклад: java RegexDemo (?itree Treehouse У цьому випадку ми забули вказати закриває метасимвол дужки ( )) у вкладеному прапорі. Ось що виводиться внаслідок цієї помилки:
regex = (?itree
input = Treehouse
Неправильное регулярное выражение: Unknown inline modifier near index 3
(?itree
   ^
Описание: Unknown inline modifier
Позиция: 3
Неправильный шаблон: (?itree

Створення корисних програм з регулярними виразами за допомогою API Regex

Регулярні вирази дозволяють створювати додатки для обробки тексту, які мають великі можливості. У цьому розділі ми покажемо вам дві зручні програми, які, сподіваємося, спонукають вас далі дослідити класи та методи API Regex. У другому додатку ви познайомитеся з Lexan: бібліотекою багаторазового коду для виконання лексичного аналізу. Регулярні вирази Java, частина 4 - 3

Регулярні вирази та документація

Документування – одне з обов'язкових завдань розробки професійно виконаного програмного забезпечення. На щастя, регулярні висловлювання можуть допомогти вам з багатьма аспектами створення документації. Код у лістингу 1 витягує рядки, що містять однорядкові та багаторядкові коментарі в стилі мови C з вихідного файлу і записує їх в інший файл. Щоб код працював, коментарі мають бути розташовані в одному рядку. Лістинг 1. Вилучення коментарів
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

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

public class ExtCmnt
{
   public static void main(String[] args)
   {
      if (args.length != 2)
      {
         System.err.println("Способ применения: java ExtCmnt infile outfile");
         return;
      }

      Pattern p;
      try
      {
         // Следующий шаблон определяет многострочные комментарии,
         // располагающиеся в одной строке (например, /* одна строка */)
            // и однострочные комментарии (например, // якая-то строка).
            // Комментарий может располагаться в любом месте строки.

         p = Pattern.compile(".*/\\*.*\\*/|.*//.*$");
      }
      catch (PatternSyntaxException pse)
      {
         System.err.printf("Синтаксическая ошибка в регулярном выражении: %s%n", pse.getMessage());
         System.err.printf("Описание ошибки: %s%n", pse.getDescription());
         System.err.printf("Позиция ошибки: %s%n", pse.getIndex());
         System.err.printf("Ошибочный шаблон: %s%n", pse.getPattern());
         return;
      }

      try (FileReader fr = new FileReader(args[0]);
           BufferedReader br = new BufferedReader(fr);
           FileWriter fw = new FileWriter(args[1]);
           BufferedWriter bw = new BufferedWriter(fw))
      {
         Matcher m = p.matcher("");
         String line;
         while ((line = br.readLine()) != null)
         {
            m.reset(line);
            if (m.matches()) /* Должна соответствовать вся строка */
            {
               bw.write(line);
               bw.newLine();
            }
         }
      }
      catch (IOException ioe)
      {
         System.err.println(ioe.getMessage());
         return;
      }
   }
}
Метод main()з лістингу 1 спочатку перевіряє правильність синтаксису командного рядка, після чого компілює призначене для виявлення одно-і багаторядкових коментарів регулярне вираження об'єкт класу Pattern. Якщо немає винятку PatternSyntaxException, спосіб main()відкриває вихідний файл, створює цільовий файл, отримує співставник для зіставлення кожного прочитаного рядка з шаблоном, після чого читає вихідний файл рядково. Для кожного рядка виконується зіставлення її із шаблоном коментаря. У разі успіху метод main()записує рядок (з наступним символом нового рядка) у цільовий файл (ми розглянемо логіку файлового вводу/виводу у майбутньому навчальному посібнику Java 101). Скомпілюйте листинг 1 таким чином: javac ExtCmnt.java Виконайте програму з файломExtCmnt.javaяк вхідний: java ExtCmnt ExtCmnt.java out Ви повинні отримати у файлі out наступні результати:
// Следующий шаблон определяет многострочные комментарии,
 // располагающиеся в одной строке (например, /* одна строка */)
    // и однострочные комментарии (например, // якая-то строка).
    // Комментарий может располагаться в любом месте строки.
p = Pattern.compile(".*/\\*.*\\*/|.*//.*$");
    if (m.matches()) /* Должна соответствовать вся строка */
У рядку шаблону .*/\\*.*\\*/|.*//.*$метасимвол вертикальної риси |грає роль логічного оператора АБО, що вказує на необхідність співставника використовувати лівий операнд з конструкції даного регулярного виразу для пошуку відповідності в тексті співставника. Якщо відповідностей немає, співставник використовує правий операнд з конструкції даного регулярного вираження для ще однієї спроби пошуку (метасимволи дужок у групі, що захоплюється, теж формують логічний оператор). Регулярні вирази в Java, частина 5
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ