使用递归替换字符串序列

时间:2013-01-22 03:07:46

标签: java string recursion replace

Java有replace()和replaceAll()方法,用给定的新模式替换字符串的部分/序列。该功能的内部如何工作?如果我必须编写一个输入字符串,OldPattern,NewPattern的函数并用NewPattern 递归替换每一次出现的OldPattern而不使用RegEx,该怎么办? 我已经使用迭代为String输入完成了以下代码,它似乎工作。如果输入是characterArray而不是字符串怎么办?

  public String replaceOld(String aInput, String aOldPattern, String aNewPattern)
        {
             if ( aOldPattern.equals("") ) {
                throw new IllegalArgumentException("Old pattern must have content.");
             }

             final StringBuffer result = new StringBuffer();
             int startIdx = 0;
             int idxOld = 0;
             while ((idxOld = aInput.indexOf(aOldPattern, startIdx)) >= 0) {
               result.append( aInput.substring(startIdx, idxOld) );
               result.append( aNewPattern );

               //reset the startIdx to just after the current match, to see
               //if there are any further matches
               startIdx = idxOld + aOldPattern.length();
             }
             //the final chunk will go to the end of aInput
             result.append( aInput.substring(startIdx) );
             return result.toString();
          }

3 个答案:

答案 0 :(得分:4)

  

Java有replace()和replaceAll()方法,用给定的新模式替换字符串的部分/序列。

确切地说,这些方法创建了新的字符串,并替换了相关的字符。 Java String是不可变的。

  

该功能的内部如何运作?

这太复杂了,不能在这里详细解释。 (实际上细节可能因实施而异)。您最好的选择是自己阅读相关库类的源代码。 (源代码作为JDK的一部分进行分发,您的Java IDE应该能够向您展示。或者,Google搜索将在网上为您找到它。)

  

如果我必须编写一个输入字符串,OldPattern,NewPattern的函数,并且在不使用RegEx的情况下递归地将NewPattern的每一次出现替换为NewPattern,该怎么办?

好吧,如果你正在谈论在不使用Pattern类的情况下进行模式匹配/替换,那么是的变得棘手......更不用说它毫无意义了。

(递归解决方案可能很危险。考虑这个问题:“递归地用”a“中的”ba“替换所有”a“实例。结果应该是什么?你是否应该尝试这样做?)< / p>


假设参数是简单的字符串(不是你描述的模式),那么这是一个递归的解决方案(未经测试):

public String replace1(String in, String target, String replacement) {
    if (target.isEmpty()) {
        return in;
    }
    int pos = in.indexOf(target);
    if (pos < 0) {
        return in;
    }
    String updated = in.substring(0, pos) + replacement + 
                     in.substring(pos + target.length());
    return replace1(updated, target, replacement);
}

解决 1 问题的版本,你希望替换是递归的;即您要替换替换过程插入的target实例的位置。如果您不想这样做,那么:

public String replace2(String in, String target, String replacement) {
    if (target.isEmpty()) {
        return in;
    }
    int pos = in.indexOf(target);
    if (pos < 0) {
        return in;
    }
    return in.substring(0, pos) + replacement + 
                     replace2(in.substring(pos + target.length()),
                             target, replacement);
}

请注意,与原始迭代解决方案相比,这些更少效率更高。甚至忽略所有正在进行的字符串复制。 Java不进行尾调用优化。


1 - 如果使用病态参数调用replace1,则会出现堆栈溢出。例如replace1("ab", "b", "b")

答案 1 :(得分:1)

public static String replaceOld(String aInput, String aOldPattern, String aNewPattern, int i) {
    i = aInput.indexOf(aOldPattern, i);
    if (i == -1) {
        return aInput;
    }
    aInput = aInput.substring(0, i) + aNewPattern + aInput.substring(i + aOldPattern.length());
    return replaceOld(aInput, aOldPattern, aNewPattern, i + aNewPattern.length());
}

请注意,param i用于优化,因此indexOf不会每次都从pos 0进行扫描。它还解决了“在”a“问题中递归替换”a“与”ba“的所有实例。

答案 2 :(得分:0)

也许这种方法会回答你的问题。

  static int indexOf(char[] string, char[] pattern, int startIndex) {
     int index = startIndex;
     while(true) {
         while(index < string.length && string[index] != pattern[0]) index++;
         if(index >= string.length || index+pattern.length > string.length) return -1;
         boolean match = true;
         for(int i = 1; i < pattern.length; i++) {
             if(string[index+i] != pattern[i]) {
                 match = false;
                 break;
             }
         }
         if(match) return index;
         else index += 1;
     }
  }

如果您需要递归替换方法,请使用此

static String replace(String string, String pattern, String replacement) {
  int index = string.indexOf(pattern);
  if(index < 0) return string;
  int endIndex = index+pattern.length();
  return string.substring(0, index) + replacement +
      replace(string.substring(endIndex), pattern, replacement);
}