Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/346.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java一次多次替换_Java_Regex - Fatal编程技术网

Java一次多次替换

Java一次多次替换,java,regex,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(

我正在尝试转换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;

    }
private-String-convertTree(String-treeOld,HashMap-conv){
Pattern=Pattern.compile(“\\(\\d+:),\\d+:”;
Matcher Matcher=pattern.Matcher(treeOld);
StringBuilder sbt=新的StringBuilder(treeOld);
while(matcher.find()){
字符串replace=conv.get(matcher.group());
System.out.println(matcher.group()+“| |”+替换+“| |”+matcher.start()+”:“+matcher.end());
删除(matcher.start(),matcher.end());
插入(matcher.start(),替换);
}
返回树;
}

虽然替换似乎有效,但对于不同大小的字符串(如示例所示),我无法获得非常正确的索引。在Java中是否有这样做的方法?

找到了它,需要使用偏移值:

private String singlePassConvert (String text, HashMap<String, String> conv) {
        Pattern pattern = Pattern.compile("\\(\\d+:|,\\d+:");
        Matcher matcher = pattern.matcher(text);
        int offset = 0;
        while (matcher.find()) {
            String replace = conv.get(matcher.group());
            String head = (String) text.subSequence(0, matcher.start() + offset);
            String tail = (String) text.subSequence(matcher.end() + offset, text.length());

            text = head + conv.get(matcher.group()) + tail;

            if (matcher.group().length() > conv.get(matcher.group()).length()) {
                offset --;
            } else if (matcher.group().length() < conv.get(matcher.group()).length()) {
                offset ++;
            }
        }
        return text;

}
私有字符串singlePassConvert(字符串文本,HashMap conv){
Pattern=Pattern.compile(“\\(\\d+:),\\d+:”;
Matcher Matcher=pattern.Matcher(文本);
整数偏移=0;
while(matcher.find()){
字符串replace=conv.get(matcher.group());
字符串头=(字符串)text.subSequence(0,matcher.start()+偏移量);
字符串尾=(字符串)text.subSequence(matcher.end()+偏移量,text.length());
text=head+conv.get(matcher.group())+tail;
if(matcher.group().length()>conv.get(matcher.group()).length()){
偏移量--;
}else if(matcher.group().length()
但是,请注意,由于此实现不使用
StringBuilder
,因此在大型字符串上可能速度较慢

此外,偏移值仅适用于+/-1长度差异,如果长度差异未知,则应修改该值。

您可以在匹配时使用该值修改字符串

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

以下是一份:

import java.util.*;
导入java.util.regex.*;
导入java.lang.*;
导入java.io.*;
表意文字
{
公共静态void main(字符串[]args)引发java.lang.Exception
{
字符串树=“(30:0.07,(1:0.06,2:0.76))”;
HashMap h=新的HashMap();
h、 付诸表决(“(1:”、“(30:);
h、 付诸表决(“,1:”,“,30:”);
h、 付诸表决(“(30:”、“(6:”);
h、 付诸表决(“,30:”,“,6:”);
System.out.println(convertTree(tree,h));
}
私有静态字符串转换树(字符串树、HashMap conv){
Pattern=Pattern.compile(“[,(]\\d+:”);//初始化正则表达式
Matcher m=pattern.Matcher(treeOld);//初始化匹配器
StringBuffer result=new StringBuffer();//声明字符串缓冲区(可以用字符串生成器替换)
而(m.find()){//遍历匹配项
if(conv.containsKey(m.group(0)){//检查密钥是否存在
m、 appendReplacement(result,conv.get(m.group(0));//如果是,则使用HashMap值
}
否则{
m、 appendReplacement(result,m.group(0));//否则,只需重新插入匹配值
}
}
m、 appendTail(result);//将剩余内容追加到结果中
返回result.toString();
}
}

你在发帖后5分钟内就解决了问题,并获得了问题的+5票和答案的+4票?看起来很可疑。@krzyk,为什么?有人可以在发帖后立即发帖并给出答案;事实上是这样。是的,这是可能的,但发帖后5分钟?有一堆新的代码?对我来说,这看起来不正确,而且如果你认为一个问题可以帮助其他人,并且你有了答案,你可以立即在同一时间发布。这没什么错。我知道这看起来很奇怪@krzyk,但实际上我已经打开了这个问题,准备在我摆弄的时候发布30分钟。我知道我已经接近这个问题了e回答,不想浪费人们的时间,应该再坚持一点!
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();

    }
}