2013-05-29 2 views
21

Допустим, у меня есть следующие строки:Как перебрать регулярное выражение

name1=gil;name2=orit; 

Я хочу, чтобы найти все матчи name=value и убедитесь, что вся строка соответствует шаблону.

Так что я сделал следующее:

  1. Убедитесь, что вся картина соответствует тому, что я хочу.

    Pattern p = Pattern.compile("^((\\w+)=(\\w+);)*$"); 
    Matcher m = p.matcher(line); 
    if (!m.matches()) { 
        return false; 
    } 
    
  2. Итерация по шаблону name=value

    Pattern p = Pattern.compile("(\\w+)=(\\w+);"); 
    Matcher m = p.matcher(line); 
    while (m.find()) { 
        map.put(m.group(1), m.group(2)); 
    } 
    

Есть ли способ сделать это с помощью одного регулярного выражения?

ответ

27

Вы можете проверить и перебрать совпадает с одним регулярным выражением на:

  • Обеспечение нет несовпадающие символы между матчами (например name1=x;;name2=y;), поставив \G в начале нашего регулярного выражения, которое означает "the end of the previous match".

  • Проверка того, достигли ли мы конца строки в нашем последнем матче, сравнивая длину нашей строки с Matcher.end(), которая возвращает смещение после последнего совпадающего символа.

Что-то вроде:

String line = "name1=gil;name2=orit;"; 
Pattern p = Pattern.compile("\\G(\\w+)=(\\w+);"); 
Matcher m = p.matcher(line); 
int lastMatchPos = 0; 
while (m.find()) { 
    System.out.println(m.group(1)); 
    System.out.println(m.group(2)); 
    lastMatchPos = m.end(); 
} 
if (lastMatchPos != line.length()) 
    System.out.println("Invalid string!"); 

Live demo.


Некоторые языки могут позволить вам перебирать отдельные матчи непосредственно с
^((\\w+)=(\\w+);)*$, но я не верю, что вы можете сделать это в Java.

2

Вы должны включить многострочный режим для «^» и «$» для работы, как ожидалось.

Pattern p = Pattern.compile("^(?:(\\w+)=(\\w+);)*$", Pattern.MULTILINE); 
while (m.find()) { 
    for (int i = 0; i < m.groupCount() - 2; i += 2) { 
     map.put(m.group(i + 1), m.group(i + 2)); 
    } 
} 

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

+0

по умолчанию regex engine соответствует многострочному режиму.did вы хотели использовать опцию dotall !.также, учитывая пример, ваше регулярное выражение не работает. – Anirudha

+0

@Anirudh: Нет, по умолчанию режим MULTILINE не включен в Java , Опция DOTALL здесь бесполезна. – nhahtdh

+0

-1, так как это не отвечает на вопрос. – nhahtdh

0
String example = "name1=gil;name2=orit;"; 
Pattern pattern = Pattern.compile("((name[0-9]+?=(.+?);))+?"); 
Matcher matcher = pattern.matcher(example); 
// verifies full match 
if (matcher.matches()) { 
    System.out.println("Whole String matched: " + matcher.group()); 
    // resets matcher 
    matcher.reset(); 
    // iterates over found 
    while (matcher.find()) { 
     System.out.println("\tFound: " + matcher.group(2)); 
     System.out.println("\t--> name is: " + matcher.group(3)); 
    } 
} 

Выход:

Whole String matched: name1=gil;name2=orit; 
    Found: name1=gil; 
    --> name is: gil 
    Found: name2=orit; 
    --> name is: orit 
+1

Это действительно 1 регулярное выражение, но оно требует 2 прохода над входной строкой (один раз в 'matches()' и один раз в цикле с 'find()') – nhahtdh

+0

@nhahtdh Вы правы. Но я не знал об ограничении «1 проход». – Mena

+1

На самом деле это не ограничение, просто сказать, что он не сильно отличается от текущего решения OP в терминах количества проходов. – nhahtdh

Смежные вопросы