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

Содержание

1 Введение
2 Использование выражений для поиска чисел
3 Поиск различающихся чисел
4 Редактирование строки
5 Ссылки

Введение

Регулярные выражения являются новой опцией Java 2 Platform, Second Edition v 1.4. Регулярное выражение представляет собой строковый шаблон, который можно использовать для выполнения изощренных операций поиска строки и замены. Например, регулярное выражение

\d+

означает "последовательность из одного или более числовых символов". Регулярное выражение представляется (компилируется в) посредством класса java.util.regex.Pattern. Затем используется соответствующий класс Matcher для поиска соответствия входной последовательности символов шаблону.

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

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

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

(\d+)zzz 

присутствуют две группы. Группа 0 всегда относится ко всему выражению, а группа 1 - к подвыражению, начинающемуся с открывающей круглой скобки "(" и заканчивающемуся закрывающей круглой скобкой ")". Текст соответствующих групп сохраняется обнаружителем соответствий регулярного выражения и может быть извлечен в дальнейшем в регулярном выражении.

Использование выражений для поиска чисел

Давайте проиллюстрируем эти идеи примером:

import java.util.regex.*;

public class GroupDemo1 {
 
static final String stringlist[] = { "abc 123 def", "456 ghi", "jkl789mno" };

 
public static void main(String args[]) {

   
// компилировать шаблон регулярного выражения для
    // числа, состоящего из одного или более цифр

   
Pattern patt = Pattern.compile("(\\d+)");

   
for (int i = 0; i < stringlist.length; i++) {
     
String currstr = stringlist[i];

     
// определить, содержит ли соответствие текущая строка

     
Matcher match = patt.matcher(currstr);

     
// если соответствие найдено - отобразить текст строки
      // для подходящей группы (группа 1)

     
if (match.find()) {
       
System.out.println("For \"" + currstr + "\" match is: "
           
+ match.group(1));
     
}
    }
  }
}

В этой демонстрации, GroupDemo1, существует несколько строк с числами. Программа использует регулярные выражения для поиска чисел и отображает строку для каждого найденного числа. В программе создается объект Matcher для каждой входной строки. Затем программа вызывает метод find для поиска соответствия шаблону регулярного выражения. Если соответствие найдено, программа извлекает соответствующий текст для группы 1 из Matcher и отображает его. В данном примере регулярное выражение равно

(\d+)

и группой 1 является текст, соответствующий "\d+". После выполнения программы вы должны увидеть следующий результат:

For "abc 123 def" match is: 123
For "456 ghi" match is: 456
For "jkl789mno" match is: 789

Поиск различающихся чисел

Рассмотрим другой пример, похожий на предыдущий:

import java.util.regex.*;

public class GroupDemo2 {
 
static final String stringlist[] = { "abc 123 def 123", "456 ghi",
     
"jkl789mno    789pqr", "123 456" };

 
public static void main(String args[]) {

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

   
Pattern patt = Pattern.compile("(\\d+).*\\1");

   
for (int i = 0; i < stringlist.length; i++) {
     
String currstr = stringlist[i];

     
// определить, содержит ли соответствие
      // текущая строка

     
Matcher match = patt.matcher(currstr);

     
// если соответствие найдено - отобразить строку для
      // соответствующей группы (группы 1)

     
if (match.find()) {
       
System.out.println("For \"" + currstr + "\" match is: "
           
+ match.group(1));
     
}
    }
  }
}

Программа GroupDemo2 почти аналогична программе GroupDemo1, но использует другое регулярное выражение:

(\d+).*\1

Для того, чтобы входная последовательность соответствовала этому выражению, она должна содержать число с последующими любыми символами, за которыми следует оригинальное число. "\1" представляет собой обратную ссылку на первую группу в выражении. То есть, входная последовательность

123 abc 123

будет соответствовать шаблону, а

 123 abc 456

не будет.

После выполнения программы GroupDemo2 вы должны увидеть следующие результаты:

For "abc 123 def 123" match is: 123
For "jkl789mno    789pqr" match is: 789

Редактирование строки

Другой способ использования групп - это редактирование строки, например, замена текста соответствующего группе другим текстом. Вот пример:

import java.util.regex.*;

public class GroupDemo3 {
 
static final String stringlist[] = { "abc 123 def   123", "456 ghi",
     
"no match", "jkl789mno   789", "", "123.123",
     
"1,2,3,4,5,6,7,8,9,10" };

 
public static void main(String args[]) {

   
// компилировать шаблон регулярного выражения для
    // числа, состоящего из одной или более
    // цифр

   
Pattern patt = Pattern.compile("(\\d+)");

   
for (int i = 0; i < stringlist.length; i++) {
     
String currstr = stringlist[i];

      String outstr;

     
// определить, содержит ли соответствие
      // текущая строка

     
Matcher match = patt.matcher(currstr);
     
boolean result = match.find();

     
// если соответствие найдено - просмотреть строку
      // и заменить все соответствия строкой
      // "[matchstring]"

     
if (result) {
       
StringBuffer strbuf = new StringBuffer();
       
do {
         
match.appendReplacement(strbuf, "[$1]");
          result = match.find
();
       
} while (result);
        match.appendTail
(strbuf);
        outstr = strbuf.toString
();
     
}

     
// если соответствие не найдено - просто
      // вывести входную строку

     
else {
       
outstr = currstr;
     
}

     
// отобразить результат

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

Программа GroupDemo3, как и предыдущие, ищет числа во входной последовательности. При обнаружении соответствия программа читает число и ставит вокруг него квадратные скобки "[]". И, наконец, программа создает выходную строку, состоящую из входной строки с выполненным над ней редактированием.

Методы appendReplacement и appendTail являются ключевыми для выполнения этой операции. Метод appendReplacement используется для замены соответствующего текста во входном потоке новой строкой, указанной вами. Строка может содержать ссылки на группы. Например, программа GroupDemo3 определяет строку замещения как "[$1]". Это означает - заменить все совпавшие фрагменты группы 1 текстом группы 1, окруженным скобками "[]", и добавить результат в выходной строковый буфер. Когда процесс поиска совпадений будет завершен, вызывается appendTail для добавления оставшейся части входной строки к выходной.

Программа GroupDemo3 отображает следующую информацию:

abc [123] def   [123]
[456] ghi
no match
jkl[789]mno   [789]

[123].[123]
[1],[2],[3],[4],[5],[6],[7],[8],[9],[10]

Логика работы этой программы аналогична логике метода Matcher.replaceAll.

Ссылки

Дополнительная информация о регулярных выражениях находится в статье "Регулярные выражения и язык программирования Java" Dane Nourie и McCloskey.

Теги: java regexp