Modo semplice per ripetere una stringa in java

Sto cercando un semplice metodo o operatore comune che mi permetta di ripetere alcune volte String n . So che potrei scrivere questo usando un ciclo for, ma vorrei evitare cicli for quando necessario e un semplice metodo diretto dovrebbe esistere da qualche parte.

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

Relativo a:

repeat string javascript Crea NSString ripetendo un’altra stringa un determinato numero di volte

Modificato

Cerco di evitare i loop quando non sono completamente necessari perché:

  1. Aggiungono al numero di righe di codice anche se sono nascoste in un’altra funzione.

  2. Qualcuno che legge il mio codice deve capire cosa sto facendo in quel ciclo. Anche se è commentato e ha nomi di variabili significative, devono comunque assicurarsi che non stia facendo nulla di “intelligente”.

  3. I programmatori amano inserire elementi intelligenti nei loop, anche se lo scrivo per “fare solo ciò che è destinato a fare”, che non preclude a qualcuno di venire avanti aggiungendo qualche ulteriore “correzione” intelligente.

  4. Spesso sono facili da sbagliare. Per i loop che coinvolgono gli indici tendono a generare un bug.

  5. I loop spesso riutilizzano le stesse variabili, aumentando la possibilità di trovare veramente degli errori di scoping.

  6. I loop aumentano il numero di posti che un cacciatore di bug deve osservare.

Da Java 11 in poi, c’è un metodo String::repeat che fa esattamente quello che hai chiesto:

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

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

Ecco la versione più corta (richiesto Java 1.5+):

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

Dove n è il numero di volte che vuoi ripetere la stringa ed s è la stringa da ripetere.

Non sono necessarie importazioni o librerie.

Commons Lang StringUtils.repeat ()

Uso:

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

In Java 8 e versioni successive c’è un modo semplice:

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

Altrimenti, questo è semplice come si ottiene:

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

String.join Java 8 fornisce un modo ordinato per farlo in combinazione con Collections.nCopies :

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

Ecco un modo per farlo usando solo le funzioni String standard e nessun ciclo esplicito:

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

Se sei come me e vuoi usare Google Guava e non Apache Commons. Puoi usare il metodo repeat nella class Guava String.

 Strings.repeat("-", 60); 

Con java-8 , puoi anche utilizzare Stream.generate .

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

e puoi avvolgerlo in un semplice metodo di utilità, se necessario:

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

Quindi vuoi evitare i loop?

Ecco qui:

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

(naturalmente so che questo è brutto e inefficiente, ma non ha loop :-p)

Lo vuoi più semplice e più carino? usa jython:

 s * 3 

Modifica : cerchiamo di ottimizzarlo un po 'MrGreen

 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 : Ho fatto un benchmark veloce e sporco per le 4 alternative principali, ma non ho il tempo di eseguirlo più volte per ottenere i mezzi e tracciare i tempi per diversi input ... Quindi ecco il codice se qualcuno vuole per provarlo:

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

Richiede 2 argomenti, il primo è il numero di iterazioni (ciascuna funzione viene eseguita con tempi di ripetizione arg da 1..n) e la seconda è la stringa da ripetere.

Finora, una rapida ispezione dei tempi che corrono con input diversi lascia la classifica qualcosa del genere (nel migliore dei casi):

  1. Iterative StringBuilder append (1x).
  2. Richiami di concatenazione log2 ricorsiva (~ 3x).
  3. Invocazioni lineari concatenazione ricorsiva (~ 30x).
  4. Concatenazione iterativa lineare (~ 45x).

Non avrei mai immaginato che la funzione ricorsiva fosse più veloce del ciclo for : -o

Buon divertimento (ctional xD).

Questo contiene meno caratteri della tua domanda

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

basato sulla risposta di Fortran, questa è una versione ricusante che 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(); } 

usare Dollar è semplice come digitare:

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

PS: la ripetizione funziona anche per array, elenco, set, ecc

Volevo una funzione per creare un elenco delimitato da virgole di punti interrogativi per scopi JDBC e ho trovato questo post. Così, ho deciso di prendere due varianti e vedere quale si comporta meglio. Dopo 1 milione di iterazioni, la varietà da giardino StringBuilder impiegava 2 secondi (divertimento1), e la versione criptica presumibilmente più ottimale (fun2) richiedeva 30 secondi. Qual è il punto di essere di nuovo criptico?

 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 classi JRE ( System.arraycopy ) e cercando di minimizzare il numero di oggetti temporanei puoi scrivere qualcosa come:

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

MODIFICARE

e senza loop puoi provare 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(", ", ""); } 

MODIFICA 2

usare Collections è ancora più breve:

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

comunque mi piace ancora la prima versione.

Soluzione OOP

Quasi ogni risposta propone una soluzione statica come soluzione, ma pensando all’Oggetto orientato agli oggetti (per scopi di riusabilità e chiarezza) ho trovato una soluzione tramite Delegazione attraverso l’Interfaccia di CharSequence (che apre anche l’usabilità alle classi mutabili di CharSequence).

La seguente class può essere utilizzata con o senza Separator-String / CharSequence e ogni chiamata a “toString ()” crea la stringa finale ripetuta. Input / Separator non sono solo limitati a String-Class, ma possono essere tutti Classi che implementano CharSequence (ad esempio StringBuilder, StringBuffer, ecc.)!

Codice sorgente:

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

Uso-Esempio:

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

Esempio-Output:

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

Se la velocità è la tua preoccupazione, allora dovresti usare meno memoria ansible. Pertanto è necessario lavorare con array di caratteri.

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

Per testare la velocità, un metodo ottimale simile usando StirngBuilder è come questo:

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

e il codice per testarlo:

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

E qui la corsa risulta dal mio sistema:

 elapsed repeatString: 6006571 elapsed repeatStringSB: 9064937 

Si noti che il test per il loop è quello di avviare JIT e ottenere risultati ottimali.

Se sei preoccupato per le prestazioni, usa un StringBuilder all’interno del ciclo e fai un .toString () all’uscita del Loop. Diamine, scrivi la tua Util Class e riutilizzala. 5 linee di codice max.

Mi piace davvero questa domanda. C’è molta conoscenza e stili. Quindi non posso lasciarlo senza mostrare il mio 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); } } 

Ti piace?

Ciclo semplice

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

Usando la ricorsione, puoi fare quanto segue (usando gli operatori ternari, una linea massima):

 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 so, è brutto e probabilmente non efficiente, ma è una sola riga!

per motivi di leggibilità e portabilità:

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

Nonostante il tuo desiderio di non usare i loop, penso che dovresti usare un loop.

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

Le tue ragioni per non usare un ciclo for non sono buone. In risposta alle tue critiche:

  1. Qualunque soluzione tu usi sarà quasi certamente più lunga di questa. Usando una funzione pre-costruita si infila solo sotto più copertine.
  2. Qualcuno che legge il tuo codice dovrà capire cosa stai facendo in quel non-ciclo. Dato che un ciclo for è il modo idiomatico per fare ciò, sarebbe molto più facile capire se lo hai fatto con un ciclo for.
  3. Sì, qualcuno potrebbe aggiungere qualcosa di intelligente, ma evitando un ciclo continuo stai facendo qualcosa di intelligente . È come spararsi intenzionalmente nel piede per evitare di spararsi per sbaglio al piede.
  4. Gli errori off-by-one sono anche incredibilmente facili da catturare con un singolo test. Dato che dovresti testare il tuo codice, un errore off-one dovrebbe essere facile da correggere e da catturare. E vale la pena notare: il codice qui sopra non contiene un errore di off-by-one. Anche i loop sono ugualmente facili da ottenere.
  5. Quindi non riutilizzare le variabili. Non è colpa del ciclo.
  6. Di nuovo, così fa qualsiasi soluzione tu usi. E come ho notato prima; un bug hunter probabilmente si aspetta che tu faccia questo con un ciclo for, quindi sarà più facile trovarlo se usi un ciclo 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); } 

Prova questo:

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