【问题标题】:Create a string with n characters创建一个包含 n 个字符的字符串
【发布时间】:2011-02-17 18:57:06
【问题描述】:

在java中有没有办法创建一个指定字符的指定数量的字符串?就我而言,我需要创建一个包含 10 个空格的字符串。我当前的代码是:

StringBuffer outputBuffer = new StringBuffer(length);
for (int i = 0; i < length; i++){
   outputBuffer.append(" ");
}
return outputBuffer.toString();

有没有更好的方法来完成同样的事情。特别是我想要一些快速的东西(在执行方面)。

【问题讨论】:

  • 如果您发现自己经常这样做,只需编写一个函数: String characterRepeat(Char c, int Length){ ... } 它可以对任何字符和任何长度执行您所做的操作。然后在需要时调用它。
  • 你想使用 StringBuilder 而不是 StringBuffer
  • 在开始时加上缓冲区的大小,便于计算和方便内存管理! StringBuilder outputBuffer = new StringBuilder(repeat * base.length());
  • 如果要追加一个空格,请改用append(' ')...它涉及的计算量少一些...

标签: java string stringbuffer


【解决方案1】:

可能是使用String API 的最短代码,专门:

String space10 = new String(new char[10]).replace('\0', ' ');

System.out.println("[" + space10 + "]");
// prints "[          ]"

作为方法,无需直接实例化char

import java.nio.CharBuffer;

/**
 * Creates a string of spaces that is 'spaces' spaces long.
 *
 * @param spaces The number of spaces to add to the string.
 */
public String spaces( int spaces ) {
  return CharBuffer.allocate( spaces ).toString().replace( '\0', ' ' );
}

调用使用:

System.out.printf( "[%s]%n", spaces( 10 ) );

【讨论】:

  • 尽管我喜欢单行,但我认为 FrustratedWithFormsDes 的解决方案在执行方面更好,因为它避免检查每个 \0 并简单地分配空间。
  • 经过测试,这总是比循环快,相当一致地快 50000-100000 纳秒,这可能非常显着(0.1 毫秒)随着迭代次数的增加,循环确实变得更快,尽管总时间还很长。这适用于创建不同大小的空间字符串时。
  • 为非常好的解决方案鼓掌,我在这里的回答中使用了它stackoverflow.com/questions/852665/…
【解决方案2】:

我强烈建议不要手动编写循环。 在您的编程生涯中,您将一遍又一遍地这样做。 阅读你的代码的人——包括你——总是需要花费时间,即使只是几秒钟,来消化循环的含义。

取而代之的是重用提供代码的可用库之一,就像StringUtils.repeatfrom Apache Commons Lang

StringUtils.repeat(' ', length);

这样您也不必担心性能,因此StringBuilder、编译器优化等的所有血腥细节都被隐藏了。 如果这个函数变得很慢,那将是库的一个错误。

使用Java 11 变得更加容易:

" ".repeat(length);

【讨论】:

  • 另一方面,如果 StringUtils 还没有在项目中使用,那么为这样一个简单的任务添加另一个依赖项可能有点过头了。
  • 如果结果很慢,您也可以提交自己的函数修复。
【解决方案3】:

嗯,现在我想起来了,也许是Arrays.fill

char[] charArray = new char[length];
Arrays.fill(charArray, ' ');
String str = new String(charArray);

当然,我假设fill 方法与您的代码执行相同的操作,因此它的执行可能大致相同,但至少行数更少。

【讨论】:

  • 在检查了源代码之后,似乎这确实完全符合 OP 发布的内容:docjar.com/html/api/java/util/Arrays.java.html 的第 806 行
  • @Lord Torgamus OP 的问题被编辑了吗?因为在我看到的版本中,他在 StringBuffer.append() 上循环,而 Frustrated 的版本正在执行填充(当然循环执行对数组的字符分配)。根本不是一回事。
  • @CPerkins,很公平,我并不清楚。我的观点是,它们都在 for 循环中逐个字符地插入。
  • @Lord Torgamus - 同意这一点。可惜jvm不能只做一个memset。我们为宽字符支付的价格。
  • @Pops 值得注意的是,如果 Arrays.fill() 函数始终用于在您的代码 (标准和外部)库代码中执行此工作,那么它会生成一个Hotspot 编译的好候选,并且更有可能找到您的 CPU 缓存。未来的 JVM 可能会将其分配为 intrinsic 函数。滚动你自己会让你远离所有这些性能优势......
【解决方案4】:

编译器会优化 for 循环。在像您这样的情况下,您不需要自己关心优化。相信编译器。

顺便说一句,如果有一种方法可以创建一个包含 n 个空格字符的字符串,那么它的编码方式与您刚才所做的相同。

【讨论】:

  • 即使这没有优化——它在你的程序中创建的频率——如果经常保存在静态变量或其他缓存中
  • btw Array.fill() 只是循环遍历数组。 /我肯定需要更多积分来评论其他帖子:)
  • @Mark Length 是可变的,因此保存它似乎很愚蠢。我该怎么办,有static Dictionary&lt;int, String&gt;
  • 存储你想要的最长的字符串,然后使用这样的东西:" ".substring(0, 10);
【解决方案5】:

Java 11

" ".repeat(10);

Java 8

generate(() -> " ").limit(10).collect(joining());

地点:

import static java.util.stream.Collectors.joining;
import static java.util.stream.Stream.generate;

【讨论】:

  • 希望 Java 可以在这里向 Python 学习.. 类似System.out.println("="*10);
  • @JGFMK 我觉得"=".repeat(10)"=" * 10 很接近。它更明确/更不容易出错(例如,python 中的'=' * 10'==========',但在java 中是610),而且不会那么长。
【解决方案6】:

在 Java 8 中,您可以使用 String.join:

String.join("", Collections.nCopies(n, s));

【讨论】:

    【解决方案7】:

    如果你只想要空格,那么如何:

    String spaces = (n==0)?"":String.format("%"+n+"s", "");
    

    这将导致 abs(n) 个空格;

    【讨论】:

    • 速度怎么样?我的印象下格式比较慢。毕竟,它必须先解析字符串才能创建它。
    【解决方案8】:

    从 Java 11 开始,您可以简单地使用 String.repeat(count) 来解决您的问题。

    返回一个字符串,其值为该字符串重复count 次的串联。

    如果此字符串为空或count 为零,则返回空字符串。

    因此,您的代码将如下所示,而不是循环:

    " ".repeat(length);
    

    【讨论】:

      【解决方案9】:

      我认为这是可能的代码更少,它使用 Guava Joiner 类:

      Joiner.on("").join(Collections.nCopies(10, ""));

      【讨论】:

      • 最短的代码行但是为这个简单的任务添加一个大型库是没有意义的。我可以使用单一方法 pubic String n(int n) { ... } 自己创建一个较小的 JAR,这将允许“更少”代码:n(10),但同样没有任何意义。
      • @isapir 对于已经在使用 Guava 的人来说,这是一个很好的答案
      • @nasch Guava 不是问题的一部分。但无论如何,在 2018 年,当您可以使用 Java 8 中添加的 String.join() 时,真的没有理由使用 Guava 的 Joiner。请参阅 stackoverflow.com/a/43011939/968244
      • @isapir 不,番石榴是一个答案。 StackOverflow 上的答案不仅仅是提问者的受众,因此如果某些答案对提问者来说不是最好的,那也没关系。关于 String.join() 的评论很棒,虽然我不确定它是否适用于所有版本的 Android,这是 Java 的一个突出用途。
      【解决方案10】:

      您可以使用标准的String.format 函数来生成 N 个空格。 例如:

      String.format("%5c", ' ');
      

      创建一个包含 5 个空格的字符串。

      int count = 15;
      String fifteenSpacebars = String.format("%" + count + "c", ' ');
      

      创建一个由 15 个空格键组成的字符串。

      如果你想重复另一个符号,你必须用你想要的符号替换空格:

      int count = 7;
      char mySymbol = '#';
      System.out.println(String.format("%" + count + "c", ' ').replaceAll("\\ ", "\\" + mySymbol));
      

      输出:

      #######
      

      【讨论】:

        【解决方案11】:

        我的贡献基于快速求幂算法。

        /**
         * Repeats the given {@link String} n times.
         * 
         * @param str
         *            the {@link String} to repeat.
         * @param n
         *            the repetition count.
         * @throws IllegalArgumentException
         *             when the given repetition count is smaller than zero.
         * @return the given {@link String} repeated n times.
         */
        public static String repeat(String str, int n) {
            if (n < 0)
                throw new IllegalArgumentException(
                        "the given repetition count is smaller than zero!");
            else if (n == 0)
                return "";
            else if (n == 1)
                return str;
            else if (n % 2 == 0) {
                String s = repeat(str, n / 2);
                return s.concat(s);
            } else
                return str.concat(repeat(str, n - 1));
        }
        

        我针对其他两种方法测试了该算法:

        • 使用 String.concat() 连接字符串的常规 for 循环
        • 使用 StringBuilder 的常规 for 循环

        测试代码(使用 for 循环和 String.concat() 的连接对于大型 n 会变得很慢,所以我在第 5 次迭代后将其省略了)。

        /**
         * Test the string concatenation operation.
         * 
         * @param args
         */
        public static void main(String[] args) {
            long startTime;
            String str = " ";
        
            int n = 1;
            for (int j = 0; j < 9; ++j) {
                n *= 10;
                System.out.format("Performing test with n=%d\n", n);
        
                startTime = System.currentTimeMillis();
                StringUtil.repeat(str, n);
                System.out
                        .format("\tStringUtil.repeat() concatenation performed in    %d milliseconds\n",
                                System.currentTimeMillis() - startTime);
        
                if (j <5) {
                    startTime = System.currentTimeMillis();
                    String string = "";
                    for (int i = 0; i < n; ++i)
                        string = string.concat(str);
                    System.out
                            .format("\tString.concat() concatenation performed in        %d milliseconds\n",
                                    System.currentTimeMillis() - startTime);
                } else
                    System.out
                            .format("\tString.concat() concatenation performed in        x milliseconds\n");
                startTime = System.currentTimeMillis();
                StringBuilder b = new StringBuilder();
                for (int i = 0; i < n; ++i)
                    b.append(str);
                b.toString();
                System.out
                        .format("\tStringBuilder.append() concatenation performed in %d milliseconds\n",
                                System.currentTimeMillis() - startTime);
            }
        }
        

        结果:

        Performing test with n=10
            StringUtil.repeat() concatenation performed in    0 milliseconds
            String.concat() concatenation performed in        0 milliseconds
            StringBuilder.append() concatenation performed in 0 milliseconds
        Performing test with n=100
            StringUtil.repeat() concatenation performed in    0 milliseconds
            String.concat() concatenation performed in        1 milliseconds
            StringBuilder.append() concatenation performed in 0 milliseconds
        Performing test with n=1000
            StringUtil.repeat() concatenation performed in    0 milliseconds
            String.concat() concatenation performed in        1 milliseconds
            StringBuilder.append() concatenation performed in 1 milliseconds
        Performing test with n=10000
            StringUtil.repeat() concatenation performed in    0 milliseconds
            String.concat() concatenation performed in        43 milliseconds
            StringBuilder.append() concatenation performed in 5 milliseconds
        Performing test with n=100000
            StringUtil.repeat() concatenation performed in    0 milliseconds
            String.concat() concatenation performed in        1579 milliseconds
            StringBuilder.append() concatenation performed in 1 milliseconds
        Performing test with n=1000000
            StringUtil.repeat() concatenation performed in    0 milliseconds
            String.concat() concatenation performed in        x milliseconds
            StringBuilder.append() concatenation performed in 10 milliseconds
        Performing test with n=10000000
            StringUtil.repeat() concatenation performed in    7 milliseconds
            String.concat() concatenation performed in        x milliseconds
            StringBuilder.append() concatenation performed in 112 milliseconds
        Performing test with n=100000000
            StringUtil.repeat() concatenation performed in    80 milliseconds
            String.concat() concatenation performed in        x milliseconds
            StringBuilder.append() concatenation performed in 1107 milliseconds
        Performing test with n=1000000000
            StringUtil.repeat() concatenation performed in    1372 milliseconds
            String.concat() concatenation performed in        x milliseconds
            StringBuilder.append() concatenation performed in 12125 milliseconds
        

        结论:

        • 对于大型 n - 使用递归方法
        • 对于小的n - for 循环有足够的速度

        【讨论】:

        • 这是一个有趣的实现。不幸的是,与您的结论相反,对于大 n 来说效率非常低。我怀疑这是因为每次连接字符串时都会进行许多内存分配。尝试将其编写为使用 StringBuilder 而不是 String 的递归方法的包装器。我打赌你会发现结果会好很多。
        • 在做微基准测试时,您需要采取很多预防措施,但我认为您没有采取任何措施!围绕这段代码的主要性能问题很容易是它是否是热点编译的,它产生了多少垃圾等等。我敢打赌,所有这些if 语句都会弄乱 CPU 的分支预测。这确实应该使用 JMH (openjdk.java.net/projects/code-tools/jmh) 重做,否则有点无意义。
        • 请注意,这个实现的复杂度是 O(n * log n),而 StringBuilder 是 O(n) :)
        【解决方案12】:

        这个怎么样?

        char[] bytes = new char[length];
        Arrays.fill(bytes, ' ');
        String str = new String(bytes);
        

        【讨论】:

        【解决方案13】:

        考虑到我们有:

        String c = "c"; // character to repeat, for empty it would be " ";
        int n = 4; // number of times to repeat
        String EMPTY_STRING = ""; // empty string (can be put in utility class)
        

        Java 8(使用流)

        String resultOne = IntStream.range(0,n)
           .mapToObj(i->c).collect(Collectors.joining(EMPTY_STRING)); // cccc
        

        Java 8(使用 nCopies)

        String resultTwo = String.join(EMPTY_STRING, Collections.nCopies(n, c)); //cccc
        

        【讨论】:

        • Collectors.joining(EMPTY_STRING) 等价于Collectors.joining()
        【解决方案14】:

        RandomStringUtils 具有从给定输入大小创建字符串的规定。 无法评论速度,但它是单线。

        RandomStringUtils.random(5,"\t");
        

        创建一个输出

        \t\t\t\t\t

        如果您不想在您的代码中看到 \0,最好使用。

        【讨论】:

          【解决方案15】:

          使用 StringUtils: StringUtils.repeat(' ', 10)

          【讨论】:

            【解决方案16】:

            使用 Guava 的最短解决方案:

            Strings.repeat(" ", len)
            

            通过Simple way to repeat a String in java

            【讨论】:

              【解决方案17】:

              这对我来说没有使用 Java 8 中的任何外部库

              String sampleText = "test"
              int n = 3;
              String output = String.join("", Collections.nCopies(n, sampleText));
              System.out.println(output);
              

              输出是

              testtesttest
              

              【讨论】:

                【解决方案18】:

                int c = 10; 字符串空格 = String.format("%" +c+ "c", ' '); 这将解决您的问题。

                【讨论】:

                  【解决方案19】:

                  在大多数情况下,您只需要达到一定长度的字符串,比如 100 个空格。您可以准备一个字符串数组,其中索引号等于空格填充字符串的大小并查找字符串,如果所需的长度在限制范围内,或者如果它在边界之外,则按需创建。

                  【讨论】:

                    【解决方案20】:

                    为了获得良好的性能,请结合aznilamirFrustratedWithFormsDesigner 的答案

                    private static final String BLANKS = "                       ";
                    private static String getBlankLine( int length )
                    {
                        if( length <= BLANKS.length() )
                        {
                            return BLANKS.substring( 0, length );
                        }
                        else
                        {
                            char[] array = new char[ length ];
                            Arrays.fill( array, ' ' );
                            return new String( array );
                        }
                    }
                    

                    根据您的要求调整BLANKS 的大小。我的具体BLANKS 字符串长度约为 200 个字符。

                    【讨论】:

                    • 我喜欢你的想法,它不是很漂亮,但很聪明。
                    【解决方案21】:

                    只需将您的 StringBuffer 替换为 StringBuilder。很难打败它。

                    如果你的长度很大,你可能会实现一些更有效的 (但更笨拙)自附加,在每次迭代中复制长度:

                     public static String dummyString(char c, int len) {
                      if( len < 1 ) return "";
                      StringBuilder sb = new StringBuilder(len).append(c);
                      int remnant = len - sb.length();
                      while(remnant  > 0) {
                       if( remnant  >= sb.length() ) sb.append(sb);
                       else sb.append(sb.subSequence(0, remnant));
                       remnant  = len - sb.length();
                      }
                      return sb.toString();
                     }
                    

                    另外,您可以尝试Arrays.fill() 方法(FrustratedWithFormsDesigner 的答案)。

                    【讨论】:

                    • 你能命名一些变量超过一个字符吗?
                    【解决方案22】:

                    您可以将StringBuffer替换为StringBuilder(后者不同步,在单线程应用中可能更快)

                    您可以创建一次StringBuilder 实例,而不是每次需要时都创建它。

                    类似这样的:

                    class BuildString {
                         private final StringBuilder builder = new StringBuilder();
                         public String stringOf( char c , int times ) {
                    
                             for( int i = 0 ; i < times ; i++  ) {
                                 builder.append( c );
                             }
                             String result = builder.toString();
                             builder.delete( 0 , builder.length() -1 );
                             return result;
                          }
                    
                      }
                    

                    并像这样使用它:

                     BuildString createA = new BuildString();
                     String empty = createA.stringOf( ' ', 10 );
                    

                    如果您将createA 作为实例变量,您可以节省创建实例的时间。

                    这不是线程安全的,如果你有多个线程,每个线程都应该有自己的副本。

                    【讨论】:

                      【解决方案23】:

                      有这样的方法。这会在给定 String 的末尾附加所需的空格,以使给定的 String 长度达到特定长度。

                      public static String fillSpaces (String str) {
                      
                          // the spaces string should contain spaces exceeding the max needed
                          String spaces = "                                                   ";
                          return str + spaces.substring(str.length());
                      }
                      

                      【讨论】:

                        【解决方案24】:

                        希望字符串具有固定大小,因此您可以填充或截断,以制表数据...

                        class Playground {
                            private static String fixStrSize(String s, int n) {
                                return String.format("%-" + n + "s", String.format("%." + n +"s", s));
                            }
                        
                            public static void main(String[ ] args) {
                                System.out.println("|"+fixStrSize("Hell",8)+"|");
                                System.out.println("|"+fixStrSize("Hells Bells Java Smells",8)+"|");
                            }
                        }
                        

                        |Hell    |
                        |Hells Be|
                        

                        优秀的参考here

                        【讨论】:

                          【解决方案25】:

                          也可以使用如下简单的方法

                          public static String padString(String str, int leng,char chr) {
                                  for (int i = str.length(); i <= leng; i++)
                                      str += chr;
                                  return str;
                              }
                          

                          【讨论】:

                          • 这是相当慢的。
                          • 您可以使用 StringBuffer 代替字符串连接,以防您处理的字符串很大。这将大大影响速度
                          【解决方案26】:

                          这个怎么样?

                          public String fillSpaces(int len) {
                              /* the spaces string should contain spaces exceeding the max needed */  
                              String spaces = "                                                   ";
                              return spaces.substring(0,len);
                          }
                          

                          编辑:我编写了一个简单的代码来测试这个概念以及我发现的内容。

                          方法一:在循环中添加单个空格:

                            public String execLoopSingleSpace(int len){
                              StringBuilder sb = new StringBuilder();
                          
                              for(int i=0; i < len; i++) {
                                  sb.append(' ');
                              }
                          
                              return sb.toString();
                            }
                          

                          方法2:追加100个空格并循环,然后是子串:

                            public String execLoopHundredSpaces(int len){
                              StringBuilder sb = new StringBuilder("          ")
                                      .append("          ").append("          ").append("          ")
                                      .append("          ").append("          ").append("          ")
                                      .append("          ").append("          ").append("          ");
                          
                              for (int i=0; i < len/100 ; i++) {
                                  sb.append("          ")
                                      .append("          ").append("          ").append("          ")
                                      .append("          ").append("          ").append("          ")
                                      .append("          ").append("          ").append("          ");
                              }
                          
                              return sb.toString().substring(0,len);
                            }
                          

                          我得到的结果是创建了 12,345,678 个空格:

                          C:\docs\Projects> java FillSpace 12345678
                          method 1: append single spaces for 12345678 times. Time taken is **234ms**. Length of String is 12345678
                          method 2: append 100 spaces for 123456 times. Time taken is **141ms**. Length of String is 12345678
                          Process java exited with code 0
                          

                          对于 10,000,000 个空格:

                          C:\docs\Projects> java FillSpace 10000000
                          method 1: append single spaces for 10000000 times. Time taken is **157ms**. Length of String is 10000000
                          method 2: append 100 spaces for 100000 times. Time taken is **109ms**. Length of String is 10000000
                          Process java exited with code 0
                          

                          结合直接分配和迭代总是花费更少的时间,创建巨大空间时平均减少 60 毫秒。对于较小的尺寸,这两个结果都可以忽略不计。

                          但请继续评论:-)

                          【讨论】:

                          • @aznilamir : 嗯,10k 个空间你会怎么做?
                          • 这个想法是结合循环和直接分配100个空间。这是代码sn-ps:
                          • 为什么要使用多个追加来添加100个字符?为什么不追加一个 100 字符?
                          【解决方案27】:

                          我知道您所询问的内容没有内置方法。但是,对于像 10 这样小的固定长度,您的方法应该非常快。

                          【讨论】:

                          • 如果它是一个小的固定长度,比如 10。
                          猜你喜欢
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2014-11-24
                          • 1970-01-01
                          • 1970-01-01
                          • 2016-04-22
                          • 1970-01-01
                          相关资源
                          最近更新 更多