【问题标题】:Java regex to extract and replace by valueJava 正则表达式按值提取和替换
【发布时间】:2019-06-19 07:22:02
【问题描述】:

输入字符串

${abc.xzy}/demo/${ttt.bbb}
test${kkk.mmm}

结果 世界/演示/你好 测试系统

大括号内的文本是我的属性的键。我想用运行时值替换这些属性。

我可以执行以下操作来获取正则表达式匹配,但我应该在替换逻辑中添加什么来更改与输入字符串中相应运行时间值匹配的 ${..}。

Pattern p = Pattern.compile("\\{([^}]*)\\}");
Matcher m = p.matcher(s);
while (m.find()) {
  // replace logic comes here
}

【问题讨论】:

标签: java regex regex-group


【解决方案1】:

另一种方法是使用第三方库,例如 Apache Commons Text。 他们的 StringSubstitutor 类看起来很有前途。

Map valuesMap = HashMap();
valuesMap.put("abc.xzy", "World");
valuesMap.put("ttt.bbb", "Hello");
valuesMap.put("kkk.mmm", "System");

String templateString = "${abc.xzy}/demo/${ttt.bbb} test${kkk.mmm}"
StringSubstitutor sub = new StringSubstitutor(valuesMap);
String resolvedString = sub.replace(templateString);

有关更多信息,请查看 Javadoc https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/StringSubstitutor.html

【讨论】:

    【解决方案2】:

    您可以使用以下解决方案:

    String s = "${abc.xzy}/demo/${ttt.bbb}\ntest${kkk.mmm}";
    Map<String, String> map = new HashMap<String, String>();
    map.put("abc.xzy", "World");
    map.put("ttt.bbb", "Hello");
    map.put("kkk.mmm", "System");
    StringBuffer result = new StringBuffer();
    Matcher m = Pattern.compile("\\$\\{([^{}]+)\\}").matcher(s);
    while (m.find()) {
        String value = map.get(m.group(1));
        m.appendReplacement(result, value != null ? value : m.group());
    }
    m.appendTail(result);
    System.out.println(result.toString());
    

    Java demo online,输出:

    World/demo/Hello
    testSystem
    

    正则表达式是

    \$\{([^{}]+)\}
    

    the regex demo。它匹配${ 字符串,然后将除{} 之外的任何1+ 字符捕获到组1 中,然后匹配}。如果第 1 组值作为键存在于 Map 中,则替换为键值,否则,匹配的文本将粘贴回输入字符串中的位置。

    【讨论】:

    • 这比我的解决方案要好。不知道 appendReplacement。相当简洁的功能。
    【解决方案3】:

    您的正则表达式需要包含美元。同样使内部组变得懒惰足以在结果键字符串中不包含任何}

    String regex = "\\$\\{(.+?)\\}";
    Pattern p = Pattern.compile(regex);
    Matcher m = p.matcher(s);
    while (m.find()) {
        String key = m.group(1); // This is your matching group (the one in braces).
        String value = someMap.get(key);    
        s.replaceFirst(regex, value != null ? value : "missingKey");
    
        m = p.matcher(s); // you could alternatively reset the existing Matcher, but just create a new one, for simplicity's sake.
    }
    

    您可以通过提取光标位置并自己替换字符串来简化此操作。但无论哪种方式,您都需要重置匹配器,否则它将解析旧字符串。

    【讨论】:

      【解决方案4】:

      The_Cute_Hedgehog 的回答很好,但包含依赖项。
      Wiktor Stribiżew 的回答缺少一个特殊情况。

      我的答案旨在使用 java 内置正则表达式,并尝试从 Wiktor Stribiżew 的答案中改进。 (仅在 Java 代码中改进,正则表达式还可以)

      改进:

      • 使用StringBuilderStringBuffer
      • 初始StringBuilder可以改成(int)(s.length()*1.2),避免在输入模板较大s的情况下多次重定位内存。
      • 避免正则表达式特殊字符的大小写由appendReplacement(如"cost: $100")产生错误结果。您可以在 Wiktor Stribiżew 的代码中解决此问题,方法是在替换字符串中转义 $ 字符,如下所示 value.replaceAll("\\$", "\\\\\\$")

      这是改进后的代码:

              String s = "khj${abc.xzy}/demo/${ttt.bbb}\ntest${kkk.mmm}{kkk.missing}string";
              Map<String, String> map = new HashMap<>();
              map.put("abc.xzy", "World");
              map.put("ttt.bbb", "cost: $100");
              map.put("kkk.mmm", "System");
              StringBuilder result = new StringBuilder((int)(s.length()*1.2));
              Matcher m = Pattern.compile("\\$\\{([^}]+)\\}").matcher(s);
              int nonCaptureIndex = 0;
              while (m.find()) {
                  String value = map.get(m.group(1));
                  if (value != null) {
                      int index = m.start();
                      if (index > nonCaptureIndex) {
                          result.append(s.substring(nonCaptureIndex, index));
                      }
                      result.append(value);
                      nonCaptureIndex = m.end();
                  }
              }
              result.append(s.substring(nonCaptureIndex, s.length()));
              System.out.println(result.toString());
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-24
        • 2019-02-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-02
        相关资源
        最近更新 更多