2016-01-19 2 views
1

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

У меня есть этот метод:

public static String processTemplate(String template, Map<String, String> attributes) { 
    Matcher m = PLACEHOLDER_PATTERN.matcher(template); 
    String message = template; 
    boolean matches = m.matches(); 

    if (matches) { 
     for (int i = 1; i < m.groupCount() + 1; i++) { 
      message = message.replaceAll(m.group(i), attributes.get(m.group(i))); 
     } 
    } 

    return message; 
} 

с этим рисунком:

private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("(\\$\\{.*?})"); 

Но этот тест не пройден:

@Test 
public void templates() { 
    Map<String, String> attributes = new HashMap<>(); 
    attributes.put("${wobble}", "wobble"); 
    String result = processTemplate("wibble ${wobble}", attributes); 
    assertEquals("wibble wobble", result); 
} 

И я не знаю, почему. Кажется, что «match» возвращает false.

+1

Тест - это только одна строка, но код продукта является многострочным –

+0

У вас нет '^' или '$' в шаблоне, 'Pattern.MULTILINE' не повлияет на ваш шаблон. 'Pattern.DOTALL' заставит символы'. 'Match newline, и у вас есть'. 'В шаблоне. –

+0

ваш шаблон «$ wobble» не имеет в нем никакой новой строки – Gavriel

ответ

2

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

private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("\\$\\{.*?}"); 

public static String processTemplate(String template, Map<String, String> attributes) { 
    Matcher m = PLACEHOLDER_PATTERN.matcher(template); 

    StringBuffer sb = new StringBuffer(); 
    while (m.find()) { 
     if (attributes.containsKey(m.group())) 
      m.appendReplacement(sb, attributes.get(m.group())); 
    } 
    m.appendTail(sb); 

    return sb.toString(); 
} 

Тогда называют его:

Map<String, String> attributes = new HashMap<>(); 
attributes.put("${wobble}", "wobble"); 
String result = processTemplate("wibble ${wobble}", attributes); 
//=> "wibble wobble" 

Изменения:

  1. Использование matcher.find() вместо matcher.matches()
  2. Использование matcher.appendReplacement() добавить каждого представителя lacement в буфер
  3. Наконец называют matcher.appendTail(), чтобы добавить оставшийся текст
+1

. Вторая проблема, которую вы решили с этим решение тоже. Оказывается, мой replaceAll не работал бы так же написано, но ваше решение прекрасно обходит эту проблему. Еще раз спасибо. –

1

Проблема заключается в том, что вы используете Matcher.matches(), которые, как говорят документы:

Попытки соответствовать всему региону с шаблоном ,

Итак, когда вы проходите в "wibble ${wobble}" матч завершается неудачей, поскольку "wibble " бит не учитывается в своем регулярном выражении.

Вместо Matcher.matches() вы должны использовать Matcher.find(), который найдет следующее частичное совпадение.

+0

Вы абсолютно правы, это была проблема, которую я пытался решить. В коде была еще одна проблема, хотя я не заметил, что замена replaceAll тоже не сработала. Это было замечено и разрешено принятым ответом. –

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