【问题标题】:Java Regex Replace with Capturing GroupJava 正则表达式替换为捕获组
【发布时间】:2010-11-19 14:45:09
【问题描述】:

有没有办法用捕获组的修改内容替换正则表达式?

例子:

Pattern regex = Pattern.compile("(\\d{1,2})");
Matcher regexMatcher = regex.matcher(text);
resultString = regexMatcher.replaceAll("$1"); // *3 ??

我想用 $1 乘以 3 替换所有出现的事件。

编辑:

好像出了点问题:(

如果我使用

Pattern regex = Pattern.compile("(\\d{1,2})");
Matcher regexMatcher = regex.matcher("12 54 1 65");
try {
    String resultString = regexMatcher.replaceAll(regexMatcher.group(1));
} catch (Exception e) {
    e.printStackTrace();
}

它抛出一个 IllegalStateException: No match found

但是

Pattern regex = Pattern.compile("(\\d{1,2})");
Matcher regexMatcher = regex.matcher("12 54 1 65");
try {
    String resultString = regexMatcher.replaceAll("$1");
} catch (Exception e) {
    e.printStackTrace();
}

工作正常,但我无法更改 $1 :(

编辑:

现在,它正在工作:)

【问题讨论】:

  • 通过直接处理字符串,我们终于有了this

标签: java regex


【解决方案1】:

Java 9 提供了一个接受替换函数的Matcher.replaceAll()

resultString = regexMatcher.replaceAll(
        m -> String.valueOf(Integer.parseInt(m.group()) * 3));

【讨论】:

    【解决方案2】:

    来源:java-implementation-of-rubys-gsub

    用法:

    // Rewrite an ancient unit of length in SI units.
    String result = new Rewriter("([0-9]+(\\.[0-9]+)?)[- ]?(inch(es)?)") {
        public String replacement() {
            float inches = Float.parseFloat(group(1));
            return Float.toString(2.54f * inches) + " cm";
        }
    }.rewrite("a 17 inch display");
    System.out.println(result);
    
    // The "Searching and Replacing with Non-Constant Values Using a
    // Regular Expression" example from the Java Almanac.
    result = new Rewriter("([a-zA-Z]+[0-9]+)") {
        public String replacement() {
            return group(1).toUpperCase();
        }
    }.rewrite("ab12 cd efg34");
    System.out.println(result);
    

    实施(重新设计):

    import static java.lang.String.format;
    
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    public abstract class Rewriter {
        private Pattern pattern;
        private Matcher matcher;
    
        public Rewriter(String regularExpression) {
            this.pattern = Pattern.compile(regularExpression);
        }
    
        public String group(int i) {
            return matcher.group(i);
        }
    
        public abstract String replacement() throws Exception;
    
        public String rewrite(CharSequence original) {
            return rewrite(original, new StringBuffer(original.length())).toString();
        }
    
        public StringBuffer rewrite(CharSequence original, StringBuffer destination) {
            try {
                this.matcher = pattern.matcher(original);
                while (matcher.find()) {
                    matcher.appendReplacement(destination, "");
                    destination.append(replacement());
                }
                matcher.appendTail(destination);
                return destination;
            } catch (Exception e) {
                throw new RuntimeException("Cannot rewrite " + toString(), e);
            }
        }
    
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append(pattern.pattern());
            for (int i = 0; i <= matcher.groupCount(); i++)
                sb.append(format("\n\t(%s) - %s", i, group(i)));
            return sb.toString();
        }
    }
    

    【讨论】:

      【解决方案3】:

      怎么样:

      if (regexMatcher.find()) {
          resultString = regexMatcher.replaceAll(
                  String.valueOf(3 * Integer.parseInt(regexMatcher.group(1))));
      }
      

      要获得第一场比赛,请使用#find()。之后,您可以使用#group(1) 引用此第一个匹配项,并将所有匹配项替换为第一个匹配值乘以 3。

      如果你想用匹配的值乘以 3 替换每个匹配:

          Pattern p = Pattern.compile("(\\d{1,2})");
          Matcher m = p.matcher("12 54 1 65");
          StringBuffer s = new StringBuffer();
          while (m.find())
              m.appendReplacement(s, String.valueOf(3 * Integer.parseInt(m.group(1))));
          System.out.println(s.toString());
      

      您可能需要查看Matcher's documentation,其中详细介绍了这一点以及更多内容。

      【讨论】:

      • 是的,但是您丢失了原始字符串。如果它是“a 1 2 3”,您将没有 a
      • 这很有帮助!一个补充是,如果你匹配一个文本并且你的匹配不是在最后,你需要调用 m.appendTail(s);
      • 在寻找带有静态文本的组时要小心,例如 Pattern.compile("var myVar=\"(.*)\";"); - 它将替换所有发现的不仅是组。另请参阅 John O 的链接。
      • @ManuelM。您可以通过使用积极的前瞻和后瞻断言而不是静态文本轻松忽略该问题。这样这些部分就不会被匹配器替换。
      • 感谢您的出色回答,您剪掉了该价值乘数示例中最有用的部分!这让我很清楚! @mezzie 非常好的补充!尽管它存在于java.util.regex.Matcher 的 Java 文档中,但对于仅引用此 SO 帖子的人来说,它将非常有帮助。 :)
      【解决方案4】:

      伯爵的回答为您提供了解决方案,但我想我会添加导致您的IllegalStateException 的问题。您在调用group(1) 之前没有先调用匹配操作(例如find())。如果您只使用$1,则不需要这样做,因为replaceAll() 是匹配操作。

      【讨论】:

        猜你喜欢
        • 2014-06-19
        • 1970-01-01
        • 2010-11-19
        • 2020-09-14
        • 2020-08-24
        • 2019-01-27
        • 1970-01-01
        • 2013-07-31
        • 1970-01-01
        相关资源
        最近更新 更多