在java中重复String的简单方法

Eth*_*man 543 java string

我正在寻找一个简单的公共方法或运算符,它允许我重复一些字符串n次.我知道我可以使用for循环来编写它,但我希望在必要时避免使用循环,并且某处应该存在一个简单的直接方法.

String str = "abc";
String repeated = str.repeat(3);

repeated.equals("abcabcabc");
Run Code Online (Sandbox Code Playgroud)

相关:

repeat string javascript 通过重复给定次数的另一个字符串来创建NSString

编辑

当他们不是完全必要的时候我试着避免循环,因为:

  1. 即使它们隐藏在另一个函数中,它们也会增加代码行数.

  2. 读我的代码的人必须弄清楚我在循环中做了什么.即使它被评论并且具有有意义的变量名称,它们仍然必须确保它没有做任何"聪明"的事情.

  3. 程序员喜欢把聪明的东西放在for循环中,即使我把它写成"只做它想要做的事情",这并不排除有人出现并增加一些额外的聪明"修复".

  4. 他们经常容易出错.对于涉及索引的循环,往往会产生一个错误.

  5. For循环经常重用相同的变量,增加了很难找到范围错误的机会.

  6. For循环增加了bug猎人必须看的地方数量.

use*_*008 862

这是最短的版本(需要Java 1.5+):

repeated = new String(new char[n]).replace("\0", s);
Run Code Online (Sandbox Code Playgroud)

n您想要重复字符串的次数在哪里,是要重复的字符串s.

不需要导入或库.

  • 对于那些抱怨混淆的人来说,可读性取决于识字能力.对于那些可能无法立即看到它的人来说,这一点非常清楚.顺便说一下,这就是Java所带来的. (70认同)
  • 虽然这非常聪明(+1)但我认为它几乎证明了for循环通常会产生更清晰的代码 (25认同)
  • 我认为它根本没有混淆.原始类型(在这种情况下为`char []`)用空值实例化,然后从`char []`创建`String`,并且用`s中所需的字符'替换'(`)` ` (20认同)
  • 为了更好的性能`...替换('\ 0',str)`应该使用而不是String版本. (10认同)
  • @ user686249:只有`replace(char oldChar,char newChar)`和`replace(CharSequence target,CharSequence replacement)`所以我看不出它是如何工作的 (10认同)
  • 这应该真的被标记为答案.当你寻找一个"简单"的解决方案时,包括外部库应该是最后的选择,如果存在更好的替代方案.这是一个非常好的选择. (9认同)
  • @javadba:不,这与"字符串分隔符的结尾"无关(此处不存在).相反,当您创建一个新数组时,所有元素都被初始化为该类型的零值; 在`char`的情况下,这是0个字符.我们只是在每次出现该角色时进行替换. (4认同)
  • 我需要使用replaceAll()来使它工作,它比新的StringBuilder(长度)和`while(repeat - > 0){sb.apend(word)}慢10倍. (2认同)
  • @ user102008准确地说:它是[_null_字符](https://en.wikipedia.org/wiki/Null_character),而不是“ 0 [零]字符”。 (2认同)

Chs*_*y76 307

Commons Lang StringUtils.repeat()

用法:

String str = "abc";
String repeated = StringUtils.repeat(str, 3);

repeated.equals("abcabcabc");
Run Code Online (Sandbox Code Playgroud)

  • 为了简单起见,使用单方法依赖从长远来看可能导致jar-hell (95认同)
  • 当然,除了它的公地郎.我不认为我曾经见过超过5000个没有公共场所的LOCS项目. (77认同)
  • 出于性能原因,我不会避免循环(请阅读我在问题中的原因).当有人看到StringUtils.repeat时,他们知道我在做什么.他们不必担心我试图编写我自己的重复版并犯了一个错误.它是一个原子认知单位! (27认同)
  • Commons Lang是开源的 - 下载并看一看.当然它内部有一个循环,但它并不那么简单.在分析和优化实现方面付出了很多努力. (10认同)
  • @ e5 - 特别是使用和重用commons类,StringUtils,可以通过多种方式减少主要负载.简单的描述性方法名称,合理的默认值和空值处理以及稳定的代码库都可以更容易地识别出更可能存在错误的位置.我鼓励的一个成语是循环控制总是使用"i"; 这会强制每个方法只有一个循环,这意味着删除了递增错误的常见问题. (7认同)
  • @ThorbjørnRavnAndersen - 如果事情不断脱离,它会变得更有趣 (6认同)
  • jar-hell的解决方案是托管构建依赖系统,例如maven.导入. (3认同)
  • @Michael Rutherfurd,这些都是生活的规则!我几个月来一直遵循"一个循环每个方法规则",它已经大大提高了我的代码的质量和可读性.当我采用两个阵列的笛卡尔积时,难以遵循"每个方法一个循环".我应该发一个关于如何做得更好的问题.Java应该添加警告'考虑使用stringUtils'. (2认同)

Can*_*ner 287

如果您使用Java <= 7,这很简单:

// create a string made up of n copies of string s
String.format("%0" + n + "d", 0).replace("0", s);
Run Code Online (Sandbox Code Playgroud)

Java 8及更高版本中,有一种简单的方法:

// create a string made up of n copies of string s
String.join("", Collections.nCopies(n, s));
Run Code Online (Sandbox Code Playgroud)

Java 11repeat?(int count)专门为此添加了一种新方法(链接)

int n = 3;
"abc".repeat(n);
Run Code Online (Sandbox Code Playgroud)

  • @Arigion`'s`必须是String,而不是`Char` (6认同)
  • 当`n`为零时,前者导致异常. (4认同)
  • 对于任何好奇的人来说,&gt;=Java 11 中新的 `"blah".repeat(10)` 似乎非常高效,直接分配字节数组,就像 `StringBuilder` 一样。可能是从现在开始重复字符串的最佳方法! (4认同)

Nic*_*lai 167

从Java 11开始,有一种方法String::repeat可以完全满足您的要求:

". ".repeat( 7 )  // Seven period-with-space pairs: . . . . . . . 
Run Code Online (Sandbox Code Playgroud)

它的Javadoc说:

String str = "abc";
String repeated = str.repeat(3);
repeated.equals("abcabcabc");
Run Code Online (Sandbox Code Playgroud)

  • Java 11计划于2018年9月推出 (10认同)
  • @Nicolai 源代码,以防万一有人关心 http://hg.openjdk.java.net/jdk/jdk/file/fc16b5f193c7/src/java.base/share/classes/java/lang/String.java# l2984 (8认同)
  • 我甚至没有在街上看过java*9*(并且不会在*长*时间......) - 并且*11*显然已经发货了.. (5认同)
  • 可能很明显,但您也可以在字符串文字上调用此方法:`"abc".repeat(3)` (5认同)

Boa*_*ann 134

Java 8 String.join提供了一种结合以下方式执行此操作的简洁方法Collections.nCopies:

// say hello 100 times
System.out.println(String.join("", Collections.nCopies(100, "hello")));
Run Code Online (Sandbox Code Playgroud)

  • 谢谢!对于android,可以使用TextUtils.join()代替String.join() (7认同)
  • 感谢您的回答。不使用任何外部API oder实用程序方法,这似乎是最干净的方法!很好!! (2认同)
  • 关于此方法的好处是,使用join可以提供分隔符,如果您要建立CSV列表,那么分隔符非常方便。使用所有其他方法,您需要有一个终止连接字符,需要在单独的操作中将其删除。 (2认同)

I. *_*edy 100

这是一种只使用标准String函数而不使用显式循环的方法:

// create a string made up of  n  copies of  s
repeated = String.format(String.format("%%%ds", n), " ").replace(" ",s);
Run Code Online (Sandbox Code Playgroud)

  • 哎哟.这很难看. (78认同)
  • 您可以使解决方案不那么难看并且更容易理解:**String.format("%0"+ n +"d",0).replace("0",s)** (15认同)
  • @mzuba让我们说`n = 3`:它首先将字符串格式化为类似`%03d`(`%%`是逃避百分号),这是添加3个填充零的格式代码,然后格式化` 0`用它,导致'000`,最后用字符串替换每个'0` (8认同)
  • 惊人的:-)虽然提防n变为零......! (5认同)
  • @Vijay Dev&fortran:不,他的意思是'replace()`.在Java 1.5+中,有一个重载版本的`replace()`需要两个`CharSequence'(包括`String`s):http://download.oracle.com/javase/1.5.0/docs/ API/JAVA/LANG/String.html#替换%28java.lang.CharSequence,%20java.lang.CharSequence 29% (4认同)

Jac*_*ack 84

如果你像我一样想要使用Google Guava而不是Apache Commons.您可以在Guava Strings类中使用repeat方法.

Strings.repeat("-", 60);
Run Code Online (Sandbox Code Playgroud)

  • @MonoThreaded我认为不言而喻,但不要包括番石榴只是做一个字符串重复.我的回答是关于你是否已经使用番石榴,那么你就是这样做的. (6认同)
  • ...并获得 3Mb 的新依赖项。 (3认同)

Ale*_* C. 49

使用,您也可以使用Stream.generate.

import static java.util.stream.Collectors.joining;
...
String repeated = Stream.generate(() -> "abc").limit(3).collect(joining()); //"abcabcabc"
Run Code Online (Sandbox Code Playgroud)

如果需要,您可以将其包装在一个简单的实用程序方法中:

public static String repeat(String str, int times) {
   return Stream.generate(() -> str).limit(times).collect(joining());
}
Run Code Online (Sandbox Code Playgroud)

  • ...或`返回IntStream.range(0,次).mapToObj(i - > str).collect(joined());`哪个更好地并行化 (6认同)

for*_*ran 32

所以你想避免循环?

在这里你有:

public static String repeat(String s, int times) {
    if (times <= 0) return "";
    else return s + repeat(s, times-1);
}
Run Code Online (Sandbox Code Playgroud)

(当然我知道这是丑陋和低效的,但它没有循环:-p)

你想要它更简单,更漂亮吗?使用jython:

s * 3
Run Code Online (Sandbox Code Playgroud)

编辑:让我们稍微优化一下:-D

public static String repeat(String s, int times) {
   if (times <= 0) return "";
   else if (times % 2 == 0) return repeat(s+s, times/2);
   else return s + repeat(s+s, times/2);
}
Run Code Online (Sandbox Code Playgroud)

编辑2:我已经为4个主要替代方案做了一个快速而肮脏的基准测试,但是我没有时间运行它几次以获取方法并绘制几个输入的时间......所以这里是代码,如果有人想要的话尝试一下:

public class Repeat {
    public static void main(String[] args)  {
        int n = Integer.parseInt(args[0]);
        String s = args[1];
        int l = s.length();
        long start, end;

        start = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            if(repeatLog2(s,i).length()!=i*l) throw new RuntimeException();
        }
        end = System.currentTimeMillis();
        System.out.println("RecLog2Concat: " + (end-start) + "ms");

        start = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            if(repeatR(s,i).length()!=i*l) throw new RuntimeException();
        }               
        end = System.currentTimeMillis();
        System.out.println("RecLinConcat: " + (end-start) + "ms");

        start = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            if(repeatIc(s,i).length()!=i*l) throw new RuntimeException();
        }
        end = System.currentTimeMillis();
        System.out.println("IterConcat: " + (end-start) + "ms");

        start = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            if(repeatSb(s,i).length()!=i*l) throw new RuntimeException();
        }
        end = System.currentTimeMillis();
        System.out.println("IterStrB: " + (end-start) + "ms");
    }

    public static String repeatLog2(String s, int times) {
        if (times <= 0) {
            return "";
        }
        else if (times % 2 == 0) {
            return repeatLog2(s+s, times/2);
        }
        else {
           return s + repeatLog2(s+s, times/2);
        }
    }

    public static String repeatR(String s, int times) {
        if (times <= 0) {
            return "";
        }
        else {
            return s + repeatR(s, times-1);
        }
    }

    public static String repeatIc(String s, int times) {
        String tmp = "";
        for (int i = 0; i < times; i++) {
            tmp += s;
        }
        return tmp;
    }

    public static String repeatSb(String s, int n) {
        final StringBuilder sb = new StringBuilder();
        for(int i = 0; i < n; i++) {
            sb.append(s);
        }
        return sb.toString();
    }
}
Run Code Online (Sandbox Code Playgroud)

它需要2个参数,第一个是迭代次数(每个函数以1..n的重复次数arg运行),第二个是要重复的字符串.

到目前为止,快速检查使用不同输入运行的时间使得排名类似于此(更好或更糟):

  1. Iterative StringBuilder追加(1x).
  2. 递归连接log2调用(~3x).
  3. 递归级联线性调用(~30x).
  4. 迭代级联线性(~45x).

我不会猜到递归函数比for循环更快:-o

玩得开心(ctional xD).

  • @ e5我希望我是Lisp黑客xD ......如果我是,我会使用尾递归功能:-p (3认同)

Pyr*_*cal 20

这包含的字符少于您的问题

public static String repeat(String s, int n) {
    if(s == null) {
        return null;
    }
    final StringBuilder sb = new StringBuilder(s.length() * n);
    for(int i = 0; i < n; i++) {
        sb.append(s);
    }
    return sb.toString();
}
Run Code Online (Sandbox Code Playgroud)

  • 除非你已经在使用Apache Commons,否则这个答案就不那么麻烦了 - 不要下载另一个库,包括它在你的类路径中,确保它的许可证与你的兼容,等等. (8认同)
  • 好吧,如果s为null,有三种方法可以处理.1.传递错误(返回null),2.隐藏错误(返回""),3.抛出NPE.隐藏错误并抛出NPE并不酷,所以我通过了错误. (7认同)
  • 请永远不要返回null - 在这种情况下返回一个空字符串,允许您始终使用未选中的返回值.否则,我会推荐海报使用. (6认同)
  • 它包含的字符多于我的回答StringUtils.repeat(str,n). (4认同)
  • @EthanHeilman 添加价值 2MB 的 `commons-lang3.3.1-sources`,你就不再那么好了 ;) 但是如果有人已经拥有 `commons-lang`,我支持你的回答。 (2认同)
  • @Pyrolistical你还可以:4.返回`"nullnullnullnull"`for`(null,4)`... (2认同)

dfa*_*dfa 9

根据fortran的回答,这是一个使用StringBuilder的重复版本:

public static void repeat(StringBuilder stringBuilder, String s, int times) {
    if (times > 0) {
        repeat(stringBuilder.append(s), s, times - 1);
    }
}

public static String repeat(String s, int times) {
    StringBuilder stringBuilder = new StringBuilder(s.length() * times);
    repeat(stringBuilder, s, times);
    return stringBuilder.toString();
}
Run Code Online (Sandbox Code Playgroud)

  • 循环而不是递归会减少大量重复的堆栈帧数。 (2认同)

dfa*_*dfa 7

使用Dollar很简单,因为输入:

@Test
public void repeatString() {
    String string = "abc";
    assertThat($(string).repeat(3).toString(), is("abcabcabc"));
}
Run Code Online (Sandbox Code Playgroud)

PS:重复也适用于数组,List,Set等

  • 是真的需要assertThat()方法吗? (3认同)

小智 7

我想要一个函数为JDBC创建一个逗号分隔的问号列表,并找到了这篇文章.所以,我决定采用两种变体,看哪哪种表现更好.经过100万次迭代后,花园种类的StringBuilder花了2秒钟(fun1),而神秘的假想更加优化的版本(fun2)耗时30秒.再次隐晦有什么意义?

private static String fun1(int size) {
    StringBuilder sb = new StringBuilder(size * 2);
    for (int i = 0; i < size; i++) {
        sb.append(",?");
    }
    return sb.substring(1);
}

private static String fun2(int size) {
    return new String(new char[size]).replaceAll("\0", ",?").substring(1);
}
Run Code Online (Sandbox Code Playgroud)

  • 我觉得第二个需要更长的时间.它正在执行字符串搜索,然后逐个字符地修改字符串. (3认同)

小智 7

OOP解决方案

几乎每个答案都提出了一个静态函数作为解决方案,但是考虑面向对象(为了可重用性和清晰度),我通过CharSequence-Interface通过委派提出了一个解决方案(这也开启了可变CharSequence-Classes的可用性).

以下类可以使用或不使用Separator-String/CharSequence,每次调用"toString()"都会构建最终重复的String.Input/Separator不仅限于String-Class,而且可以是每个实现CharSequence的Class(例如StringBuilder,StringBuffer等)!

源代码:

/**
 * Helper-Class for Repeating Strings and other CharSequence-Implementations
 * @author Maciej Schuttkowski
 */
public class RepeatingCharSequence implements CharSequence {
    final int count;
    CharSequence internalCharSeq = "";
    CharSequence separator = "";
    /**
     * CONSTRUCTOR - RepeatingCharSequence
     * @param input CharSequence to repeat
     * @param count Repeat-Count
     */
    public RepeatingCharSequence(CharSequence input, int count) {
        if(count < 0)
            throw new IllegalArgumentException("Can not repeat String \""+input+"\" less than 0 times! count="+count);
        if(count > 0)
            internalCharSeq = input;
        this.count = count;
    }
    /**
     * CONSTRUCTOR - Strings.RepeatingCharSequence
     * @param input CharSequence to repeat
     * @param count Repeat-Count
     * @param separator Separator-Sequence to use
     */
    public RepeatingCharSequence(CharSequence input, int count, CharSequence separator) {
        this(input, count);
        this.separator = separator;
    }

    @Override
    public CharSequence subSequence(int start, int end) {
        checkBounds(start);
        checkBounds(end);
        int subLen = end - start;
        if (subLen < 0) {
            throw new IndexOutOfBoundsException("Illegal subSequence-Length: "+subLen);
        }
        return (start == 0 && end == length()) ? this
                    : toString().substring(start, subLen);
    }
    @Override
    public int length() {
        //We return the total length of our CharSequences with the separator 1 time less than amount of repeats:
        return count < 1 ? 0
                : ( (internalCharSeq.length()*count) + (separator.length()*(count-1)));
    }
    @Override
    public char charAt(int index) {
        final int internalIndex = internalIndex(index);
        //Delegate to Separator-CharSequence or Input-CharSequence depending on internal index:
        if(internalIndex > internalCharSeq.length()-1) {
            return separator.charAt(internalIndex-internalCharSeq.length());
        }
        return internalCharSeq.charAt(internalIndex);
    }
    @Override
    public String toString() {
        return count < 1 ? ""
                : new StringBuilder(this).toString();
    }

    private void checkBounds(int index) {
        if(index < 0 || index >= length())
            throw new IndexOutOfBoundsException("Index out of Bounds: "+index);
    }
    private int internalIndex(int index) {
        // We need to add 1 Separator-Length to total length before dividing,
        // as we subtracted one Separator-Length in "length()"
        return index % ((length()+separator.length())/count);
    }
}
Run Code Online (Sandbox Code Playgroud)

使用情况的示例:

public static void main(String[] args) {
    //String input = "12345";
    //StringBuffer input = new StringBuffer("12345");
    StringBuilder input = new StringBuilder("123");
    //String separator = "<=>";
    StringBuilder separator = new StringBuilder("<=");//.append('>');
    int repeatCount = 2;

    CharSequence repSeq = new RepeatingCharSequence(input, repeatCount, separator);
    String repStr = repSeq.toString();

    System.out.println("Repeat="+repeatCount+"\tSeparator="+separator+"\tInput="+input+"\tLength="+input.length());
    System.out.println("CharSeq:\tLength="+repSeq.length()+"\tVal="+repSeq);
    System.out.println("String :\tLength="+repStr.length()+"\tVal="+repStr);

    //Here comes the Magic with a StringBuilder as Input, as you can append to the String-Builder
    //and at the same Time your Repeating-Sequence's toString()-Method returns the updated String :)
    input.append("ff");
    System.out.println(repSeq);
    //Same can be done with the Separator:
    separator.append("===").append('>');
    System.out.println(repSeq);
}
Run Code Online (Sandbox Code Playgroud)

示例 - 输出:

Repeat=2    Separator=<=    Input=123   Length=3
CharSeq:    Length=8    Val=123<=123
String :    Length=8    Val=123<=123
123ff<=123ff
123ff<====>123ff
Run Code Online (Sandbox Code Playgroud)

  • 这真可笑. (8认同)
  • 我很少见过令人恶心的事情:/ (3认同)

dfa*_*dfa 6

仅使用JRE类(System.arraycopy)并尝试最小化临时对象的数量,您可以编写如下内容:

public static String repeat(String toRepeat, int times) {
    if (toRepeat == null) {
        toRepeat = "";
    }

    if (times < 0) {
        times = 0;
    }

    final int length = toRepeat.length();
    final int total = length * times;
    final char[] src = toRepeat.toCharArray();
    char[] dst = new char[total];

    for (int i = 0; i < total; i += length) {
        System.arraycopy(src, 0, dst, i, length);
    }

    return String.copyValueOf(dst);
}
Run Code Online (Sandbox Code Playgroud)

编辑

没有循环你可以尝试:

public static String repeat2(String toRepeat, int times) {
    if (toRepeat == null) {
        toRepeat = "";
    }

    if (times < 0) {
        times = 0;
    }

    String[] copies = new String[times];
    Arrays.fill(copies, toRepeat);
    return Arrays.toString(copies).
              replace("[", "").
              replace("]", "").
              replaceAll(", ", "");
}
Run Code Online (Sandbox Code Playgroud)

编辑2

使用集合甚至更短:

public static String repeat3(String toRepeat, int times) {
    return Collections.nCopies(times, toRepeat).
           toString().
           replace("[", "").
           replace("]", "").
           replaceAll(", ", "");
}
Run Code Online (Sandbox Code Playgroud)

不过我还是喜欢第一个版本.

  • 你试过用例如repeat3("[,]",5)吗? (6认同)
  • -1:太聪明了一半.如果您的目标是使代码可读或有效,那么这些"解决方案"并不是一个好主意.可以使用StringBuilder(设置初始容量)简单地重写'repeat'.并且'repeat2'/'r​​epeat3'实际上是低效的,并且取决于String [].toString()生成的String的未指定语法. (6认同)

Pan*_*tis 5

如果您关心速度,则应使用尽可能少的内存复制。因此,需要使用字符数组。

public static String repeatString(String what, int howmany) {
    char[] pattern = what.toCharArray();
    char[] res = new char[howmany * pattern.length];
    int length = pattern.length;
    for (int i = 0; i < howmany; i++)
        System.arraycopy(pattern, 0, res, i * length, length);
    return new String(res);
}
Run Code Online (Sandbox Code Playgroud)

为了测试速度,使用StirngBuilder的类似最佳方法是这样的:

public static String repeatStringSB(String what, int howmany) {
    StringBuilder out = new StringBuilder(what.length() * howmany);
    for (int i = 0; i < howmany; i++)
        out.append(what);
    return out.toString();
}
Run Code Online (Sandbox Code Playgroud)

和测试它的代码:

public static void main(String... args) {
    String res;
    long time;

    for (int j = 0; j < 1000; j++) {
        res = repeatString("123", 100000);
        res = repeatStringSB("123", 100000);
    }

    time = System.nanoTime();
    res = repeatString("123", 1000000);
    time = System.nanoTime() - time;
    System.out.println("elapsed repeatString: " + time);

    time = System.nanoTime();
    res = repeatStringSB("123", 1000000);
    time = System.nanoTime() - time;
    System.out.println("elapsed repeatStringSB: " + time);

}
Run Code Online (Sandbox Code Playgroud)

这是我的系统的运行结果:

elapsed repeatString: 6006571
elapsed repeatStringSB: 9064937
Run Code Online (Sandbox Code Playgroud)

请注意,对循环的测试是启动JIT并获得最佳结果。


Sim*_*mon 5

不是最短的,但是(我认为)最快的方法是使用StringBuilder:

 /**
   * Repeat a String as many times you need.
   *
   * @param i - Number of Repeating the String.
   * @param s - The String wich you want repeated.
   * @return The string n - times.
   */
  public static String repeate(int i, String s) {
    StringBuilder sb = new StringBuilder();
    for (int j = 0; j < i; j++)
      sb.append(s);
    return sb.toString();
  }
Run Code Online (Sandbox Code Playgroud)


Kap*_*lan 5

一个简单的单行解决方案:
需要 Java 8

Collections.nCopies( 3, "abc" ).stream().collect( Collectors.joining() );
Run Code Online (Sandbox Code Playgroud)