Java 一次多次替换

标签 java regex

我正在尝试翻译 newick 格式树上的节点,但我无法正确替换。假设我有 HashMap:

"(1:" : "(30:"
",1:" : ",30:" 
"(30:" : "(6:"
",30:" : ",6:"

还有那棵树:

(30:0.07,(1:0.06,2:0.76))

传统观点建议使用多个replaceAll,但这会带来一个问题:

replaceAll("(1:", "(30:") >> (30:0.07,(30:0.06,2:0.76))
replaceAll("(30:", "(6:") >> (6:0.07,(6:0.06,2:0.76))

这里的问题是我们替换了一个之前被替换过的节点。正确的树应该是这样的:

(6:0.07,(30:0.06,2:0.76))

现在我已经用 Python 完成了这个:

def multiple_replace(taxa, text): 
    regex = re.compile("|".join(map(re.escape, taxa.keys())))
    return regex.sub(lambda mo: taxa[mo.group(0)], text) 

但是我的 Java 实现遇到了问题:

private String convertTree (String treeOld, HashMap<String, String> conv) {
        Pattern pattern = Pattern.compile("\\(\\d+:|,\\d+:");
        Matcher matcher = pattern.matcher(treeOld);
        StringBuilder sbt = new StringBuilder(treeOld);
        while (matcher.find()) {
            String replace = conv.get(matcher.group());
            System.out.println(matcher.group() + "||" +replace + " || " + matcher.start() + ":"+matcher.end());
            sbt.delete(matcher.start(), matcher.end());
            sbt.insert(matcher.start(), replace);
        }
        return treeOld;

    }

虽然替换似乎有效,但对于不同大小的字符串(如示例所示),我无法获得完全正确的索引。有没有办法在 Java 中执行此操作?

最佳答案

您可以使用 Matcher#appendReplacement在匹配时修改您的字符串。

请注意,您的正则表达式可以简化为 [,(]\d+:,因为您的替代分支仅在第一个字符上有所不同([,(] 匹配 ()。

这是一个 IDEONE demo :

import java.util.*;
import java.util.regex.*;
import java.lang.*;
import java.io.*;

class Ideone
{
    public static void main (String[] args) throws java.lang.Exception
    {
        String tree = "(30:0.07,(1:0.06,2:0.76))";
        HashMap<String, String> h = new HashMap<String, String>();
        h.put("(1:" , "(30:");
        h.put(",1:" , ",30:");
        h.put("(30:" , "(6:");
        h.put(",30:" , ",6:");
        System.out.println(convertTree(tree, h));

    }
    private static String convertTree(String treeOld, HashMap<String, String> conv) {
        Pattern pattern = Pattern.compile("[,(]\\d+:");  // Init the regex
        Matcher m = pattern.matcher(treeOld);            // Init the matcher
        StringBuffer result = new StringBuffer();        // Declare the string buffer (can be replaced with a string builder)
        while (m.find()) {                               // Iterate through matches
            if (conv.containsKey(m.group(0))) {          // Check if the key exists
                m.appendReplacement(result, conv.get(m.group(0))); // If yes, use the HashMap value
            }
            else {
                m.appendReplacement(result, m.group(0));  // Else, just reinsert the match value
            }
        }
        m.appendTail(result);        // Append what remains to the result
        return result.toString();

    }
}

关于Java 一次多次替换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37235976/

相关文章:

java - 无法解析方法 get width 和 getHeight

java - 如何让 FOP 仅在语言不支持时读取外部字体

regex - 说两个字母具有相同的量词而不在正则表达式中指定数字

regex - 匹配 Perl 中的最后一个正则表达式模式

javascript - 将目的地分为城市、地区和国家

java - Java 中的 tan() 返回一个奇怪的值

java - 从mysql表中获取元素到arraylist

java - Apache Storm 尝试本地主机 Zookeeper 连接,而不是指定的 Zookeeper 服务器列表

regex - 非贪婪的 nginx 位置正则表达式返回 404 错误

ruby - 如何打印 Ruby 正则表达式变量?