Java一次多次替换
我正在尝试转换newick格式树上的节点,但在正确替换节点时遇到了问题。假设我有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(
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();
}
}