2016-10-10 3 views
3

Использование Java 7 и RegEx по умолчанию implementatiin в java.util.regex.Pattern, учитывая регулярное выражение, как это:Замена неоднократно происходящих групп из привязанного регулярных выражений в Java

^start (m[aei]ddel[0-9] ?)+ tail$

И строка, как это :

start maddel1 meddel2 middel3 tail

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

start <match> <match> <match> tail.

я могу получить каждую группу без якорей, как это:

Regex: m[aei]ddel[0-9]

StringBuffer sb = new StringBuffer(); 
Matcher matcher = pattern.matcher(input); 
while (matcher.find()) { 
    matcher.appendReplacement(sb, Matcher.quoteReplacement("<middle>")); 
} 

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

Однако, когда я добавляю якоря, единственный API, который я могу найти, требует целого соответствия и доступа к последнему вхождению группы. В моем случае мне нужно проверить правильность регулярного выражения (т. Е. Целое совпадение), но на этапе замены мне нужно иметь доступ к каждой группе самостоятельно.

Редактировать Я хотел бы избежать обходных решений, таких как поиск якорей в отдельном шаге, потому что это потребует больших изменений кода и обертывания его всего в RegExes.

+0

вы просто заменяя каждый 'maddle' с ''? –

+0

да, я не думаю, что мне нужно делать больше задач в согласованной последовательности – Mene

+0

Чтобы уточнить: 'm [aei] ddel [0-9]' - просто пример, мои текущие регулярные выражения более сложны, и каждое регулярное выражение будет иметь другая замена. Важным моментом является то, что мне нужно заменить каждое появление группы matche своей собственной заменой, и регулярное выражение должно быть привязано. – Mene

ответ

2

Чтобы сделать это за один шаг, вам необходимо использовать регулярное выражение \G, которое будет выполнять привязку. Тем не менее, вам также нужен положительный результат, чтобы проверить, заканчивается ли строка с требуемым шаблоном.

Вот регулярное выражение, которое должно работать:

(^start|(?!\A)\G)\s+m[aei]ddel[0-9](?=(?:\s+m[aei]ddel[0-9])*\s+tail$) 

См regex demo

String s = "start maddel1 meddel2 middel3 tail"; 
String pat = "(^start|(?!\\A)\\G)\\s+(m[aei]ddel[0-9])(?=(?:\\s+m[aei]ddel[0-9])*\\s+tail$)"; 
System.out.println(s.replaceAll(pat, "$1 <middle>")); 

См Java online demo

Объяснение:

  • (^start|(?!\A)\G) - матч start в конце строки или конец предыдущего успешного матча
  • \s+ - 1 или более пробельные символы
  • m[aei]ddel[0-9] - m, то либо a, e, i, затем ddel, затем 1 цифра
  • (?=(?:\s+m[aei]ddel[0-9])*\s+tail$) - только если следуют с:
    • (?:\s+m[aei]ddel[0-9])* - ноль или более последовательностей 1+ и пробелов middelN шаблон
    • \s+ - 1 или более
    • пробелы
    • tail$ - tails подстроки следуют с конца строки.
+0

Good что регулярное выражение anubhava будет соответствовать другому входу.Жалкие вещи становятся намного сложнее (синтаксис мудрый и требующий обходных циклов). Я дам ему попытку и надеюсь, что мои товарищи по команде смогут жить с немного более страшными выглядящими регулярными выражениями;) – Mene

+1

Если вы не хотите жестко кодировать пробелы, переместите шаблон пробелов в группу 1, см. Http://ideone.com/5nPrri. Вы все еще можете использовать двухэтапный подход, сначала перенесив строку с ''^start. * Tail \\ z "', а затем замените то, что вам нужно. –

3

Вы можете использовать \G для этого:

final String regex = "(^start |(?<!^)\\G)m[aei]ddel[0-9] (?=.* tail$)"; 
final String str = "start maddel1 meddel2 middel3 tail"; 

String repl = str.replaceAll(regex, "$1<match> "); 
//=> start <match> <match> <match> tail 

RegEx Demo

\G утверждает положение в конце предыдущего матча или в начале строки для первого матча.

+3

Это регулярное выражение также найдет совпадения в строке, например ['start maddel1 meddel2 middel3 something else tail'] (https://regex101.com/r/G6OqBh/2) –

2

С \G якорем, для метода find, вы можете написать так:

pat = "\\G(?:(?!\\A) |\\Astart (?=(?:m[aei]ddel[0-9])+tail\\z))(m\\S+)"; 

деталь:

\\G # position after the previous match or at the start of the string 
    # putting it in factor makes fail the pattern more quickly after the last match 
(?: 
    (?!\\A) [ ] # a space not at the start of the string 
       # this branch is the first one because it has more chance to succeed 
    | 
    \\A start [ ] # "start " at the beginning of the string 
    (?=(?:m[aei]ddel[0-9])+tail\\z) # check the string format once and for all 
            # since this branch will succeed only once 
) 
(# capture group 1 
    m\\S+ # the shortest and simplest pattern that matches "m[aei]ddel[0-9]" 
      # and excludes "tail" (adapt it to your need but keep the same idea) 
) 

demo

+1

Я откровенно, как и ваши решения. – revo

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