在java中重复一个string的简单方法
我正在寻找一个简单的公共方法或运算符,允许我重复一些stringn次。 我知道我可以用for循环写这个,但是我希望在必要的时候避免使用循环,并且在某个地方应该存在一个简单的直接方法。
String str = "abc"; String repeated = str.repeat(3); repeated.equals("abcabcabc");
相关:
重复stringJavaScript 创buildNSString重复另一个string给定的次数
编辑
我试图避免循环时,他们是不完全必要的,因为:
-
即使它们被隐藏在另一个函数中,它们也会增加代码的行数。
-
有人阅读我的代码必须弄清楚我在做什么循环。 即使它被评论并且有一个有意义的variables名,他们仍然必须确保它没有做任何“聪明”的事情。
-
程序员喜欢把巧妙的东西放在循环中,即使我把它写成“只做它打算做的事情”,也不排除有人来,并增加一些额外的聪明的“修复”。
-
他们很容易出错。 对于涉及索引的循环往往会产生一个错误。
-
对于循环往往重用相同的variables,增加真正难以发现范围的错误的机会。
-
For循环增加了猎人必须看的地方的数量。
这是如此简单:
// create a string made up of n copies of string s String.format("%0" + n + "d", 0).replace("0",s);
在Java 8中有一个更简单的方法:
// create a string made up of n copies of string s String.join("", Collections.nCopies(n, s));
这是最短的版本(需要Java 1.5+):
repeated = new String(new char[n]).replace("\0", s);
其中n
是要重复string的次数, s
是要重复的string。
没有import或图书馆需要。
Commons Lang StringUtils.repeat()
用法:
String str = "abc"; String repeated = StringUtils.repeat(str, 3); repeated.equals("abcabcabc");
Java 8的String.join
提供了一个完整的方法来与Collections.nCopies
结合使用:
// say hello 100 times System.out.println(String.join("", Collections.nCopies(100, "hello")));
这里有一个方法只使用标准的string函数,并没有显式的循环:
// create a string made up of n copies of s repeated = String.format(String.format("%%%ds", n), " ").replace(" ",s);
如果你像我一样,想使用Google Guava而不是Apache Commons。 您可以在Guava Strings类中使用repeat方法。
Strings.repeat("-", 60);
用java-8 ,你也可以使用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 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); }
编辑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(); } }
它需要2个参数,第一个是迭代次数(每个函数以1..n的重复次数运行),第二个是要重复的string。
到目前为止,对不同投入的时间进行快速检查会导致排名如此之差(好坏):
- 迭代StringBuilder追加(1x)。
- recursion级联log2调用(〜3x)。
- recursion级联线性调用(〜30x)。
- 迭代级联线性(〜45x)。
我永远不会猜测recursion函数比for
循环快:-o
玩得开心(ctional xD)。
这包含比你的问题更less的字符
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(); }
基于fortran的回答 ,这是一个使用StringBuilder的recusive版本:
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(); }
使用美元很简单,因为input:
@Test public void repeatString() { String string = "abc"; assertThat($(string).repeat(3).toString(), is("abcabcabc")); }
PS:对于数组,列表,集合等重复工作也是如此
我想要一个函数为JDBC目的创build一个以逗号分隔的问号列表,并find了这个post。 所以,我决定采取两个变种,看看哪一个更好。 经过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); }
只使用JRE类( System.arraycopy )并尽量减less临时对象的数量,你可以写如下所示的东西:
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(", ", ""); }
但是我仍然喜欢第一个版本。
OOP解决scheme
几乎每个答案都提出了一个静态函数作为解决scheme,但是考虑面向对象(为了重用性和清晰度),我通过CharSequence接口(这也打开了可变CharSequence类的可用性)提出了一个通过委托的解决scheme。
以下类可以使用或不使用Separator-String / CharSequence,每次调用“toString()”构build最终重复的String。 input/分隔符不仅限于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
如果您担心性能,只需在循环内使用StringBuilder,然后在Loop的出口处执行.toString()。 嘿,写你自己的Util类并重用它。 5行代码最大。
我真的很喜欢这个问题。 有很多的知识和风格。 所以我不能放弃我的摇滚乐;)
{ 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 string, int times) { StringBuilder out = new StringBuilder(); while (times-- > 0) { out.append(string); } return out.toString(); }
使用recursion,你可以做下面的事情(使用三元运算符,最多一行):
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)); }
我知道,这很丑,可能效率不高,但这是一条线!
为了可读性和便携性:
public String repeat(String str, int count){ if(count <= 0) {return "";} return new String(new char[count]).replace("\0", str); }
尽pipe你不想使用循环,我想你应该使用循环。
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循环的原因是不好的。 回应你的批评:
- 无论你使用什么解决scheme,肯定会比这个更长。 使用预buildfunction只能将其包藏在更多的封面下。
- 有人读你的代码将不得不弄清楚你在做什么非循环。 鉴于for循环是这样做的惯用方法,如果你用for循环做了,会容易得多。
- 是的,有人可能会添加一些聪明的东西,但是通过避免for循环, 你正在做一些聪明的事情 。 这就像是有意的在脚下自我射击,以避免意外地在脚下自己射击。
- 通过单一testing,逐个错误也是非常容易的。 鉴于你应该testing你的代码,一个错误的错误应该很容易修复和捕获。 值得注意的是:上面的代码不包含错误的错误。 For循环同样容易得到正确的。
- 所以不要重复使用variables。 这不是for-loop的错。
- 再一次,无论你使用什么解决scheme。 正如我之前指出的那样; 一个bug猎手可能会期待你用for循环做这个,所以如果你使用for循环,他们会更容易find它。
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 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; }
我创build了一个recursion的方法,做同样的事情,你想..随意使用这个…
public String repeat(String str, int count) { return count > 0 ? repeat(str, count -1) + str: ""; }
我有相同的答案我可以乘以java中的string重复序列?
如果速度是你所关心的,那么你应该使用尽可能less的内存复制。 因此需要使用字符数组。
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); }
为了testing速度,使用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(); }
和testing它的代码:
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
请注意,循环testing是踢JIT,并有最佳的结果。
这里是最新的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(); } }
it doesn't even need to be this big, can be made into this, and can be copied and pasted into a utility class in your project.
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(); }
So e5, I think the best way to do this would be to simply use the above mentioned code,or any of the answers here. but commons lang is just too big if it's a small project
Not the shortest, but (i think) the fastest way is to use the 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(); }
repeated = str + str + str;
Sometimes simple is best. Everyone reading the code can see what's happening.
And the compiler will do the fancy stuff with StringBuilder
behind the scenes for you.
Here is a simple way to repeat a star a number of times (up to some known maximum):
String stars = "*****".substring(0, n);