简单的方法来重复一个字符串

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

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


repeated.equals("abcabcabc");

相关:

重复字符串JavaScript 通过重复另一个字符串给定次数来创建NSString

编辑

我尽量避免for循环,因为它们不是完全必要的:

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

  2. 阅读我代码的人必须弄清楚我在for循环中做了什么。即使它被注释并有有意义的变量名称,他们仍然必须确保它没有做任何“聪明”的事情。

  3. 程序员喜欢在for循环中加入聪明的东西,即使我写它“只做它打算做的事情”,这并不排除有人来添加一些额外的聪明“修复”。

  4. 它们通常很容易出错。因为涉及索引的循环往往会产生一个错误。

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

  6. 循环增加了bug猎人必须寻找的地方的数量。

740785 次浏览

Commons LangStringUtils.repeat()

用法:

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


repeated.equals("abcabcabc");

如果您担心性能,只需在循环内使用StringBuilder并在循环退出时执行. toString()。见鬼,编写自己的Util类并重用它。最多5行代码。

这包含的字符比你的问题少

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();
}

仅使用 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);
}

剪辑

没有循环,你可以尝试:

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(", ", "");
}

编辑2

使用 收款的时间更短:

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

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

尽管你不想用循环,但我觉得你应该用循环。

String repeatString(String s, int repetitions)
{
if(repetitions < 0) throw SomeException();


else if(s == null) return null;


StringBuilder stringBuilder = new StringBuilder(s.length() * repetitions);


for(int i = 0; i < repetitions; i++)
stringBuilder.append(s);


return stringBuilder.toString();
}

您没有使用 for 循环的理由并不充分:

  1. 无论使用什么解决方案,几乎可以肯定都会比这个时间长。使用一个预先构建的功能,只能把它藏在更多的封面下。
  2. 读取您代码的人必须弄清楚您在非 for 循环中正在做什么。考虑到 for 循环是实现这一点的惯用方法,如果使用 for 循环来实现这一点将会容易得多。
  3. 是的,有人可能会添加一些聪明的东西,但是通过避免 for 循环 你正在做一些聪明的事情。这就像故意射自己的脚以避免不小心射到自己的脚。
  4. 一个错误之外的错误也非常容易被一个测试捕捉到。考虑到你应该测试你的代码,一个差一错误应该很容易修复和捕捉。值得注意的是,上面的代码没有包含差一错误。因为循环同样容易正确。
  5. 所以不要重用变量,这不是 for 循环的错。
  6. 同样,您使用的任何解决方案也是如此。正如我之前提到的,bug 搜索者可能希望您使用 for 循环来完成这项工作,所以如果您使用 for 循环,他们将更容易找到它。

所以你想避免循环?

现在你看到了:

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

(当然,我知道这很难看,效率很低,但是它没有循环: -p)

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

s * 3

编辑 : 让我们对它进行一些优化:-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);
}

Edit2 : 我已经为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();
}
}

它有两个参数,第一个是迭代次数(每个函数运行的重复次数从1开始)。.N) ,第二个是要重复的字符串。

到目前为止,快速检查一下不同输入的运行时间,排名如下(从好到坏) :

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

我从来没有想到递归函数会比 for循环快:-o

玩得开心(ctionalxD)。

基于 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();
}

下面是一种只使用标准字符串函数而不使用显式循环的方法:

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

使用 一美元很简单,只需输入:

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

重复也适用于数组、列表、集合等

以下是最简短的版本(需要 Java 1.5 +) :

repeated = new String(new char[n]).replace("\0", s);

其中,n是要重复字符串的次数,而 s是要重复的字符串。

不需要导入或库。

如果你使用的是 Java < = 7,那么它就是最“简洁”的:

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

爪哇8及以上版本中,有一种更易读的方法:

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

最后,对于 爪哇11及以上版本,有一个专门用于此目的的新 repeat​(int count)方法(链接)

"abc".repeat(12);

或者,如果您的项目使用 java 库,则有更多选项。

对于 阿帕奇共享(Apache Commons):

StringUtils.repeat("abc", 12);

对于 Google Guava < a href = “ https://Guava.dev/release/20.0/api/docs/com/Google/common/base/Strings.html # repeat-java.lang.String-int-”rel = “ noReferrer”> Google Guava :

Strings.repeat("abc", 12);

这是最新的 Stringutils.java StringUtils.java

    public static String repeat(String str, int repeat) {
// Performance tuned for 2.0 (JDK1.4)


if (str == null) {
return null;
}
if (repeat <= 0) {
return EMPTY;
}
int inputLength = str.length();
if (repeat == 1 || inputLength == 0) {
return str;
}
if (inputLength == 1 && repeat <= PAD_LIMIT) {
return repeat(str.charAt(0), repeat);
}


int outputLength = inputLength * repeat;
switch (inputLength) {
case 1 :
return repeat(str.charAt(0), repeat);
case 2 :
char ch0 = str.charAt(0);
char ch1 = str.charAt(1);
char[] output2 = new char[outputLength];
for (int i = repeat * 2 - 2; i >= 0; i--, i--) {
output2[i] = ch0;
output2[i + 1] = ch1;
}
return new String(output2);
default :
StringBuilder buf = new StringBuilder(outputLength);
for (int i = 0; i < repeat; i++) {
buf.append(str);
}
return buf.toString();
}
}

它甚至不需要这么大,可以做成这个,可以复制粘贴 转换为项目中的实用程序类。

    public static String repeat(String str, int num) {
int len = num * str.length();
StringBuilder sb = new StringBuilder(len);
for (int i = 0; i < times; i++) {
sb.append(str);
}
return sb.toString();
}

所以 e5,我认为最好的方法是简单地使用上面提到的代码,或者这里的任何答案。但如果是个小项目,commons lang 就太大了

如果你像我一样想用谷歌番石榴而不是 Apache Commons。可以在 GuavaStrings 类中使用 重复方法。

Strings.repeat("-", 60);

我需要一个函数来为 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);
}

我真的很喜欢这个问题。有很多知识和风格。所以我不能不展示我的摇滚乐就离开它;)

{
String string = repeat("1234567890", 4);
System.out.println(string);
System.out.println("=======");
repeatWithoutCopySample(string, 100000);
System.out.println(string);// This take time, try it without printing
System.out.println(string.length());
}


/**
* The core of the task.
*/
@SuppressWarnings("AssignmentToMethodParameter")
public static char[] repeat(char[] sample, int times) {
char[] r = new char[sample.length * times];
while (--times > -1) {
System.arraycopy(sample, 0, r, times * sample.length, sample.length);
}
return r;
}


/**
* Java classic style.
*/
public static String repeat(String sample, int times) {
return new String(repeat(sample.toCharArray(), times));
}


/**
* Java extreme memory style.
*/
@SuppressWarnings("UseSpecificCatch")
public static void repeatWithoutCopySample(String sample, int times) {
try {
Field valueStringField = String.class.getDeclaredField("value");
valueStringField.setAccessible(true);
valueStringField.set(sample, repeat((char[]) valueStringField.get(sample), times));
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}

你喜欢吗?

public static String repeat(String str, int times) {
int length = str.length();
int size = length * times;
char[] c = new char[size];
for (int i = 0; i < size; i++) {
c[i] = str.charAt(i % length);
}
return new String(c);
}

简单的循环

public static String repeat(String string, int times) {
StringBuilder out = new StringBuilder();
while (times-- > 0) {
out.append(string);
}
return out.toString();
}

试试这个:

public static char[] myABCs = {'a', 'b', 'c'};
public static int numInput;
static Scanner in = new Scanner(System.in);


public static void main(String[] args) {
System.out.print("Enter Number of Times to repeat: ");
numInput = in.nextInt();
repeatArray(numInput);
}


public static int repeatArray(int y) {
for (int a = 0; a < y; a++) {
for (int b = 0; b < myABCs.length; b++) {
System.out.print(myABCs[b]);
}
System.out.print(" ");
}
return y;
}

Java8的 String.join提供了一种与 Collections.nCopies一起完成这项工作的简洁方法:

// say hello 100 times
System.out.println(String.join("", Collections.nCopies(100, "hello")));
repeated = str + str + str;

有时候简单是最好的,每个读代码的人都能看到发生了什么。

编译器将在后台为您完成 StringBuilder的花哨工作。

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

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

如果需要的话,你可以用一个简单的实用方法把它包装起来:

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

使用递归,您可以执行以下操作(使用三元运算符,最大值为一行) :

public static final String repeat(String string, long number) {
return number == 1 ? string : (number % 2 == 0 ? repeat(string + string, number / 2) : string + repeat(string + string, (number - 1) / 2));
}

我知道,这很难看,可能效率不高,但这只是一句台词!

OOP 解决方案

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

下面的类可以使用或不使用分隔符-String/CharSequence,并且每个对“ toString ()”的调用都构建最终重复的 String。 输入/分隔符不仅仅局限于 String-Class,而且可以是实现 CharSequence 的每个类(例如 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);
}
}

用法-例如:

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);
}

示例-输出:

Repeat=2    Separator=<=    Input=123   Length=3
CharSeq:    Length=8    Val=123<=123
String :    Length=8    Val=123<=123
123ff<=123ff
123ff<====>123ff

我创建了一个递归方法,它可以做你想做的事情,你可以随意使用这个..。

public String repeat(String str, int count) {
return count > 0 ?  repeat(str, count -1) + str: "";
}

我在 我可以在 java 中用字符串相乘来重复序列吗?上也有同样的答案

为了便于阅读和携带:

public String repeat(String str, int count){
if(count <= 0) {return "";}
return new String(new char[count]).replace("\0", str);
}

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

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);
}

为了测试速度,使用 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();
}

以及测试它的代码:

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);


}

这是我系统的运行结果:

elapsed repeatString: 6006571
elapsed repeatStringSB: 9064937

注意,循环测试将启用 JIT 并获得最佳结果。

不是最短的,但是 (我想)最快的方法是使用 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();
}

String::repeat

". ".repeat(7)  // Seven period-with-space pairs: . . . . . . .

Java11 中的新方法是 String::repeat,它完全满足您的要求:

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

贾瓦多克表示:

/**
* Returns a string whose value is the concatenation of this
* string repeated {@code count} times.
* <p>
* If this string is empty or count is zero then the empty
* string is returned.
*
* @param count number of times to repeat
*
* @return A string composed of this string repeated
* {@code count} times or the empty string if this
* string is empty or count is zero
*
* @throws IllegalArgumentException if the {@code count} is
* negative.
*
* @since 11
*/
public static String rep(int a,String k)


{
if(a<=0)
return "";
else
{a--;
return k+rep(a,k);
}

您可以使用这种递归方法来实现所需的目标。

直截了当的一句话解决方案:
需要 Java 8

Collections.nCopies( 3, "abc" ).stream().collect( Collectors.joining() );

综合供快速参考:

public class StringRepeat {


// Java 11 has built-in method - str.repeat(3);
// Apache - StringUtils.repeat(3);
// Google - Strings.repeat("",n);
// System.arraycopy


static String repeat_StringBuilderAppend(String str, int n) {


if (str == null || str.isEmpty())
return str;


StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
sb.append(str);
}
return sb.toString();
}


static String repeat_ArraysFill(String str, int n) {
String[] strs = new String[n];
Arrays.fill(strs, str);
return Arrays.toString(strs).replaceAll("\\[|\\]|,| ", "");
}


static String repeat_Recursion(String str, int n) {
if (n <= 0)
return "";
else
return str + repeat_Recursion(str, n - 1);
}


static String repeat_format1(String str, int n) {
return String.format(String.format("%%%ds", n), " ").replace(" ", str);
}


static String repeat_format2(String str, int n) {
return new String(new char[n]).replace("\0", str);
}


static String repeat_format3(String str, int n) {
return String.format("%0" + n + "d", 0).replace("0", str);
}


static String repeat_join(String str, int n) {
return String.join("", Collections.nCopies(n, str));
}


static String repeat_stream(String str, int n) {
return Stream.generate(() -> str).limit(n).collect(Collectors.joining());
}


public static void main(String[] args) {
System.out.println(repeat_StringBuilderAppend("Mani", 3));
System.out.println(repeat_ArraysFill("Mani", 3));
System.out.println(repeat_Recursion("Mani", 3));
System.out.println(repeat_format1("Mani", 3));
System.out.println(repeat_format2("Mani", 3));
System.out.println(repeat_format3("Mani", 3));
System.out.println(repeat_join("Mani", 3));
System.out.println(repeat_stream("Mani", 3));


}

}

如果您只知道输出字符串的 长度(它可能不能被输入字符串的长度整除) ,那么使用以下方法:

static String repeat(String s, int length) {
return s.length() >= length ? s.substring(0, length) : repeat(s + s, length);
}

使用说明:

for (int i = 0; i < 50; i++)
System.out.println(repeat("_/‾\\", i));

不要在空 slength > 0的情况下使用,因为在这种情况下不可能获得所需的结果。