【问题标题】:Efficient way to replace chars in a string (java)?替换字符串中的字符的有效方法(java)?
【发布时间】:2012-01-05 02:58:54
【问题描述】:

我正在编写一个小的 JAVA 程序:

  • 将文本作为字符串
  • 需要 2 个字符数组

我尝试做的事情听起来像是“查找和替换”,但它不一样,所以我认为清除它很重要。

无论如何我想获取此文本,查找第一个数组中的任何字符是否与文本中的字符匹配,如果是,则将其替换为第二个字符数组中的匹配字符(根据索引)。

我会用一个例子来解释: 假设我的文本(字符串)是:“java 很棒!”; 我有 2 个数组(char[]):“absm”和“!@*$”。

希望的结果是将 'a' 更改为 '!' , 'b' 到 '@' 等等.. 意味着结果文本将是:

“java 太棒了!”改为 -> "j@v@ i* @w*o$e!"

最有效的方法是什么?为什么? 我想过循环文本,但后来发现效率不高。

StringBuilder/可以使用String类)

【问题讨论】:

  • 让我们看看你到目前为止做了什么
  • 如果你想将a替换成!,如何获取j@v@

标签: java string replace char stringbuilder


【解决方案1】:

此实用程序类替换字符串的一个字符或一组字符。相当于bashtr和perltr///,又名,音译。

/**
 * Utility class that replaces chars of a String, aka, transliterate.
 * 
 * It's equivalent to bash 'tr' and perl 'tr///'.
 *
 */
public class ReplaceChars {

    public static String replace(String string, String from, String to) {
        return new String(replace(string.toCharArray(), from.toCharArray(), to.toCharArray()));
    }

    public static char[] replace(char[] chars, char[] from, char[] to) {

        char[] output = chars.clone();
        for (int i = 0; i < output.length; i++) {
            for (int j = 0; j < from.length; j++) {
                if (output[i] == from[j]) {
                    output[i] = to[j];
                    break;
                }
            }
        }
        return output;
    }

    /**
     * For tests!
     */
    public static void main(String[] args) {

        // Example from: https://en.wikipedia.org/wiki/Caesar_cipher
        String string = "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG";
        String from = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        String to = "XYZABCDEFGHIJKLMNOPQRSTUVW";

        System.out.println();
        System.out.println("Cesar cypher: " + string);
        System.out.println("Result:       " + ReplaceChars.replace(string, from, to));
    }
}

这是输出:

Cesar cypher: THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
Result:       QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD

【讨论】:

    【解决方案2】:

    对于像这样的小东西, indexOf() 搜索可能比地图更快,同时“避免”接受答案的内部循环。当然,循环仍然存在,在 String.indexOf() 中,但它很可能会被 JIT 编译器优化为告别,因为它被大量使用。

    static String replaceChars(String source, String from, String to)
    {
        StringBuilder dest = new StringBuilder(source);
        for ( int i = 0; i < source.length(); i++ )
        {
            int foundAt = from.indexOf(source.charAt(i));
            if ( foundAt >= 0 )
                dest.setCharAt(i,to.charAt(foundAt));
        }
        return dest.toString();
    }
    

    更新:Oracle/Sun JIT 至少在一些处理器上为 indexOf() 使用了SIMD,这使得它比人们想象的还要快。

    【讨论】:

    • 我尝试了接受的解决方案和您的解决方案。而且我发现您的解决方案运行得更快(2 次)。非常感谢!
    【解决方案3】:

    我猜你正在寻找StringUtils.replaceEach,至少作为参考。

    【讨论】:

    • 似乎正是 OP 正在寻找的。​​span>
    • OP 要求高效。这需要可变长度的字符串数组,而不是字符,这使得它的效率有些低。
    【解决方案4】:
    StringBuilder sb = new StringBuilder(text);
        for(int i = 0; i<text.length(); i ++)
        {
            for (int j = 0; j < firstCharArray.length;j++)
            {
                if (sb.charAt(i) == firstCharArray[j])
                {
                    sb.setCharAt(i, secondCharArray[j]);
                    break;
                }
    
            }
        }
    

    这种方式很有效,因为它使用 StringBuilder 来更改字符(如果您使用字符串,则每次都必须创建新的,因为它们是不可变的。)此外,它还最大限度地减少了您必须执行的传递次数( 1 传递文本字符串,n 传递第一个数组,其中 n = text.length())

    【讨论】:

    • 好吧,这就是我想要做的。我刚刚测试了您的代码,它运行良好!非常感谢。 **一个小问题:**此代码循环文本中的每个字符,并且对于每个字符,它循环第一个字符数组。对于文本中的第二个字符的含义,我们将再次循环第一个字符,我猜没有其他方法了吗? :S
    • 如果文本中的第二个字符是数组中的第一个字符怎么办?
    • 我不太明白你的意思?也许这是我的错,我刚刚读了我上一篇文章写给你的内容,无论如何我不清楚我的意思......假设我有一个长度为 4 的字符串和两个数组,而它们中的两个大小相同让我们说长度为 2。起初我们迭代文本的 1/4 字符,然后遍历整个数组 (x2),然后迭代 2/4 字符.. 以此类推,我们一次又一次地检查相同的选项,所以我不确定它的效率如何..
    【解决方案5】:

    由于知道是否应该替换字符的唯一方法是检查它,因此您(或任何 util 方法)必须循环遍历整个文本,一个字符一个接一个。您永远无法获得比 O(n) 更好的复杂性(n 是文本中的字符数)。

    【讨论】:

      【解决方案6】:

      将您拥有的 2 个数组放入地图中

      Map<Character, Character> //or Map of Strings
      

      其中键是“a”、“b”等......而值是您要替换的字符 - “@”等......

      然后只需将字符串中的键替换为值即可。

      【讨论】:

      • 谢谢,但这个例子太高级了,因为我不应该使用这个对象。
      • 没问题。只是以后要考虑的事情。
      【解决方案7】:

      您需要它的效率如何?你这样做是为了成百上千、上百万字吗???

      我不知道它是否最有效,但是您可以在每个可能的标记上使用字符串 indexOf() 方法,它会告诉您它是否存在,然后您可以同时替换该索引与另一个数组中的相应字符。

      代码方面,类似于(顺便说一句,这是半伪代码):

      for(each of first array) {
          int temp = YourString.indexOf(current array field);
          if (temp >=0) {
              replace with other array
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2016-10-28
        • 1970-01-01
        • 1970-01-01
        • 2018-03-28
        • 2011-07-25
        • 2012-10-26
        • 2012-09-25
        相关资源
        最近更新 更多