替换子串的优雅解决方案

时间:2015-07-22 21:20:43

标签: java string substring

我遇到了一个具有挑战性的问题,我遇到了麻烦。我有一个未修改的字符串,例如abcdefg和一个包含字符串和索引的对象数组。

例如,对象1包含d和索引[1, 2];

然后我会用[1,2]替换子串d处的任何字母,结果字符串看起来像adcdefg

当替换文本的长度与替换文本的长度不同时,问题就出现了。我需要一些方法来跟踪长度变化,否则进一步替换的指数将是不准确的。

这是我到目前为止所做的:

 for (CandidateResult cResult : candidateResultList) {
      int[] index = cResult.getIndex();

      finalResult = finalResult.substring(0, index[0]) + cResult.getCandidate()
              + finalResult.substring(index[1], finalResult.length()); //should switch to stringbuilder
 }
 return finalResult;

这不会照顾上面提到的角落情况。

此外,如果有人想知道,这不是功课。这实际上是我创建的ocr培训师计划。

3 个答案:

答案 0 :(得分:2)

这是一个实现,我还没有测试过,但你可以尝试一个想法。我会根据需要在代码中添加注释。

/** This class represents a replacement of characters in the original String, s[i0:if], 
  *  with a new string, str. 
 **/
class Replacement{
    int s, e;
    String str;
    public Replacement(int s, int e, String str){ 
        this.s = s;
        this.e = e;
        this.str = str;
    }
}

String stringReplace(String str, List<Replacement> replacements){

    // Sort Replacements by starting index
    Collections.sort(replacements, new Comparator<Replacement>(){
        @Override public int compare(Replacement r1, Replacement r2){
            return Integer.compare(r1.s, r2.s);
        }
    };

    StringBuilder sb = new StringBuilder();
    int repPos = 0;

    for(int i = 0; i < str.length; i++){
        Replacement rep = replacements.get(repPos);
        if(rep.s == i){               // Replacement starts here, at i == s
            sb.append(rep.str);       // Append the replacement
            i = rep.e - 1;            // Advance i -> e - 1
            repPos++;                 // Advance repPos by 1
        } else {
            sb.append(str.charAt(i)); // No replacement, append char
        }
    }

    return sb.toString();
}

[编辑:] 在看到ptyx的答案后,我认为这种方式可能更优雅。如果按相反的顺序排序,则不必担心不同的长度:

String stringReplace(String str, List<Replacement> replacements){

    // Sort Replacements in reverse order by index 
    Collections.sort(replacements, new Comparator<Replacement>(){
        @Override public int compare(Replacement r1, Replacement r2){
            return -Integer.compare(r1.s, r2.s);  // Note reverse order
        }
    };

    // By replacing in reverse order, shouldn't affect next replacement.
    StringBuilder sb = new StringBuilder(str);
    for(Replacement rep : replacements){
        sb.replace(rep.s, rep.e, rep.str);
    }

    return sb.toString();
}

答案 1 :(得分:1)

假设没有要替换的重叠范围,请按反向位置顺序处理您的替换 - 完成。

替换[5-6]并不重要,它永远不会修改[0-4],因此您不需要为任何索引映射而烦恼,例如:[1 ,2]

答案 2 :(得分:1)

这似乎就像你问的那样,基本上你只是根据以前的插入来翻译替换

public static void main(String[] args) {
    Replacer[] replacers = {
            new Replacer(new int[]{ 1 , 2 }, "ddd") ,
            new Replacer(new int[]{ 2 , 3 }, "a")
    };
    System.out.println(
            m("abcdefg", replacers));
}

public static String m(String s1, Replacer[] replacers){
    StringBuilder builder = new StringBuilder(s1);
    int translate = 0;
    for (int i = 0 ; i < replacers.length ; i++) {
        translate += replacers[i].replace(builder, translate);
    }
    return builder.toString();
}

public static class Replacer{
    int[] arr;
    String toRep;

    public Replacer(int[] arr, String toRep) {
        this.arr = arr;
        this.toRep = toRep;
    }

    public int replace(StringBuilder b, int translate){
        b.replace(arr[0] + translate, arr[1] + translate, toRep);
        return arr[1];
    }
}