Manera simple de repetir una cadena en Java

Estoy buscando un método simple u operador común que me permita repetir algunas cadenas n veces. Sé que podría escribir esto usando un bucle for, pero deseo evitar bucles siempre que sea necesario y un método directo simple debería existir en alguna parte.

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

Relacionado con:

cadena de repetición javascript Crea NSString repitiendo otra cadena un determinado número de veces

Editado

Intento evitar bucles cuando no son completamente necesarios porque:

  1. Agregan a la cantidad de líneas de código, incluso si están escondidas en otra función.

  2. Alguien que lea mi código tiene que descubrir lo que estoy haciendo en ese ciclo for. Incluso si se comenta y tiene nombres de variables significativas, aún deben asegurarse de que no está haciendo algo “inteligente”.

  3. A los progtwigdores les encanta poner cosas ingeniosas en bucles, incluso si lo escribo para “hacer solo lo que se pretende”, eso no impide que alguien se acerque y agregue alguna “solución” inteligente adicional.

  4. A menudo son fáciles de equivocarse. Para bucles que implican índices tienden a generar un error por uno.

  5. Para los bucles, a menudo se reutilizan las mismas variables, lo que aumenta las posibilidades de encontrar errores de búsqueda realmente difíciles.

  6. Para los bucles aumenta la cantidad de lugares que debe buscar un cazador de errores.

Desde Java 11 en adelante, hay un método String::repeat que hace exactamente lo que usted solicitó:

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

Su Javadoc dice:

 /** * Returns a string whose value is the concatenation of this * string repeated {@code count} times. * 

* 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 */

Aquí está la versión más corta (se requiere Java 1.5+):

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

Donde n es el número de veces que desea repetir la cadena y s es la cadena para repetir.

No se necesitan importaciones o bibliotecas.

Commons Lang StringUtils.repeat ()

Uso:

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

En Java 8 y superior hay una manera fácil:

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

De lo contrario, esto es tan simple como se pone:

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

El String.join Java 8 proporciona una forma ordenada de hacerlo en conjunto con Collections.nCopies :

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

Esta es una forma de hacerlo utilizando solo funciones de cadena estándar y sin bucles explícitos:

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

Si eres como yo y quieres usar Google Guava y no Apache Commons. Puedes usar el método de repetición en la clase Guava Strings.

 Strings.repeat("-", 60); 

Con java-8 , también puedes usar Stream.generate .

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

y puede envolverlo en un sencillo método de utilidad si es necesario:

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

¿Entonces quieres evitar los bucles?

Aqui lo tienes:

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

(Por supuesto, sé que esto es feo e ineficiente, pero no tiene bucles :-p)

¿Quieres que sea más simple y más bonita? usa jython:

 s * 3 

Edición : optimicémoslo un poco 😀

 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 : He hecho un benchmark rápido y sucio para las 4 alternativas principales, pero no tengo tiempo para ejecutarlo varias veces para obtener los medios y trazar los tiempos para varias entradas ... Así que aquí está el código si alguien quiere intentarlo:

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

Toma 2 argumentos, el primero es el número de iteraciones (cada función se ejecuta con repeticiones arg de 1..n) y la segunda es la cadena para repetir.

Hasta ahora, una inspección rápida de los tiempos que corren con diferentes entradas deja el ranking algo como esto (de mejor a peor):

  1. Iterative StringBuilder append (1x).
  2. Invocaciones recursivas de concatenación de log2 (~ 3x).
  3. Invocaciones recursivas de concatenación lineal (~ 30x).
  4. Concatenación iterativa lineal (~ 45x).

Nunca hubiera adivinado que la función recursiva era más rápida que el ciclo for : -o

Diviértete (ctional xD).

Esto contiene menos caracteres que tu pregunta

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

basado en la respuesta de Fortran , esta es una versión recusiva que usa un 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(); } 

usar Dollar es simple como escribir:

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

PD: repetir funciona también para array, List, Set, etc.

Quería una función para crear una lista delimitada por comas de signos de interrogación para fines de JDBC, y encontré esta publicación. Entonces, decidí tomar dos variantes y ver cuál funcionaba mejor. Después de 1 millón de iteraciones, el StringBuilder tipo jardín tardó 2 segundos (fun1), y la versión crípticamente supuestamente más óptima (fun2) tardó 30 segundos. ¿Cuál es el punto de ser críptico otra vez?

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

usando solo clases JRE ( System.arraycopy ) y tratando de minimizar la cantidad de objetos temporales, puede escribir algo como:

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

EDITAR

y sin bucles puedes probar con:

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

EDIT 2

usar colecciones es aún más corto:

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

sin embargo, todavía me gusta la primera versión.

Solución OOP

Casi todas las respuestas proponen una función estática como solución, pero al pensar en Orientado a Objetos (con fines de reutilización y claridad) se me ocurrió una Solución a través de la Delegación a través de la Interfaz CharSecuencia (que también abre usabilidad en CharSequence-Class mutable).

La siguiente clase se puede usar con o sin Separator-String / CharSequence y cada llamada a “toString ()” crea la cadena final repetida. El Input / Separator no solo se limita a String-Class, sino que también puede ser de cada clase que implemente CharSequence (por ejemplo, StringBuilder, StringBuffer, etc.).

Código fuente:

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

Ejemplo de uso:

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

Ejemplo de salida:

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

Si la velocidad es su problema, debe usar menos copias de memoria como sea posible. Por lo tanto, se requiere trabajar con matrices de caracteres.

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

Para probar la velocidad, un método óptimo similar que utiliza StirngBuilder es así:

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

y el código para probarlo:

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

Y aquí la ejecución resulta de mi sistema:

 elapsed repeatString: 6006571 elapsed repeatStringSB: 9064937 

Tenga en cuenta que la prueba de bucle es patear JIT y tener resultados óptimos.

Si le preocupa el rendimiento, simplemente use un StringBuilder dentro del bucle y realice un .toString () al salir del bucle. Diablos, escribe tu propia Clase Util y vuelve a utilizarla. 5 líneas de código máx.

Realmente disfruto esta pregunta. Hay muchos conocimientos y estilos. Así que no puedo dejarlo sin mostrar mi rock and roll;)

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

¿Te gusta?

Bucle simple

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

Usando la recursión, puede hacer lo siguiente (usando operadores ternarios, una línea máxima):

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

Lo sé, es feo y probablemente no eficiente, ¡pero es una sola línea!

por el bien de la legibilidad y la portabilidad:

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

A pesar de su deseo de no utilizar bucles, creo que debería usar un bucle.

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

Sus razones para no usar un bucle for no son buenas. En respuesta a tus críticas:

  1. Cualquier solución que uses seguramente será más larga que esto. El uso de una función preconstruida solo lo coloca debajo de más cubiertas.
  2. Alguien que lea tu código tendrá que descubrir qué estás haciendo en ese bucle que no es para. Dado que un bucle for es la forma idiomática de hacer esto, sería mucho más fácil averiguar si lo hiciste con un bucle for.
  3. Sí, alguien podría agregar algo inteligente, pero al evitar un bucle for está haciendo algo inteligente . Es como dispararse en el pie intencionalmente para evitar dispararse en el pie por accidente.
  4. Los errores de uno por uno también son increíblemente fáciles de atrapar con una sola prueba. Dado que debería probar su código, un error aislado debería ser fácil de corregir y atrapar. Y vale la pena señalar: el código anterior no contiene un error "uno por uno". Para los bucles es igualmente fácil hacerlo bien.
  5. Entonces no reutilices las variables. Eso no es culpa del for-loop.
  6. De nuevo, también lo hace cualquier solución que use. Y como noté antes; un cazador de errores probablemente espera que hagas esto con un bucle for, por lo que les resultará más fácil encontrarlo si usas un bucle for.
 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); } 

Probar esto:

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

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

here is the latest 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

I created a recursive method that do the same thing you want.. feel free to use this…

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

i have the same answer on Can I multiply strings in java to repeat sequences?

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