Простой способ повторить строку в java

Я ищу простой метод или оператор commons, который позволяет мне повторять несколько строк n раз. Я знаю, что я мог бы написать это, используя цикл for, но я бы хотел, чтобы избежать циклов, когда это необходимо, и простой простой метод должен существовать где-то.

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

repeated.equals("abcabcabc");

Связано с:

повторить строку javascript Создайте NSString, повторив другую строку определенное количество раз

Edited

Я стараюсь избегать циклов, когда они не являются полностью необходимыми, потому что:

  • Они добавляют к числу строк кода, даже если они спрятаны в другой функции.

  • Кто-то, читающий мой код, должен выяснить, что я делаю в этом цикле. Даже если он прокомментирован и имеет значащие имена переменных, им все равно нужно убедиться, что он не делает ничего "умного".

  • Программисты любят вкладывать умные вещи в циклы, даже если я пишу это, чтобы "делать то, что он должен делать", что не мешает кому-то прийти и добавить дополнительное умное "исправление".

  • Они очень часто ошибаются. Для циклов, включающих индексы, имеют тенденцию генерировать один баг.

  • Для циклов часто повторяются одни и те же переменные, что увеличивает вероятность очень трудно найти ошибки.

  • Для циклов увеличивайте количество мест, в которых должен выглядеть искатель ошибок.

Ответ 1

String::repeat

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

В Java 11 появился метод String::repeat, который делает именно то, что вы просили:

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

Его Javadoc говорит:

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

Ответ 2

Вот кратчайшая версия (требуется Java 1.5+):

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

Где n - это количество раз, когда вы хотите повторить строку, а s - это строка, которую нужно повторить.

Импорт или библиотеки не требуется.

Ответ 3

Commons Lang StringUtils.repeat()

Использование:

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

repeated.equals("abcabcabc");

Ответ 4

Если вы используете Java & lt; = 7, это так просто:

// 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 11 добавил новый метод repeat​(int count) специально для этого (ссылка)

int n = 3;
"abc".repeat(n);

Ответ 5

Java 8 String.join обеспечивает удобный способ сделать это в сочетании с Collections.nCopies:

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

Ответ 6

Здесь вы можете сделать это, используя только стандартные функции String и явные петли:

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

Ответ 7

Если вы похожи на меня и хотите использовать Google Guava, а не Apache Commons. Вы можете использовать метод repeat в классе Guava Strings.

Strings.repeat("-", 60);

Ответ 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());
}

Ответ 9

Итак, вы хотите избежать циклов?

Здесь у вас есть:

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

Требуется 2 аргумента, первое - количество итераций (каждая функция запускается с периодом повторения arg от 1..n), а вторая - это строка для повторения.

До сих пор быстрый просмотр времени, выполняющегося с разными входами, оставляет рейтинг чем-то вроде этого (лучше хуже):

  • Iterative StringBuilder добавляет (1x).
  • Рекурсивные конкатенации log2-вызовы (~ 3x).
  • Рекурсивная конкатенация линейных вызовов (~ 30x).
  • Итеративная конкатенация линейная (~ 45x).

Я бы никогда не догадался, что рекурсивная функция работает быстрее, чем цикл for: -o

Удачи (ctional xD).

Ответ 10

Это содержит меньше символов, чем ваш вопрос

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

Ответ 11

на основе ответа 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();
}

Ответ 12

с помощью Dollar прост, как печатать:

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

PS: repeat работает также для массива, списка, набора и т.д.

Ответ 13

Я хотел, чтобы функция создавала список вопросительных знаков с разделителями-запятыми для целей JDBC и нашла это сообщение. Итак, я решил взять два варианта и посмотреть, какой из них лучше. После 1 миллиона итераций садовое разнообразие 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);
}

Ответ 14

Решение ООП

Почти каждый ответ предлагает статическую функцию как решение, но, думая об объектно-ориентированном (для целей повторного использования и ясности), я придумал решение через делецию через CharSequence-Interface (что также открывает удобство использования изменчивого CharSequence- Классы).

Следующий класс можно использовать либо с разделителем-строкой/CharSequence, либо без него, и каждый вызов toString() "создает финальную повторяющуюся строку. Вход/Сепаратор не ограничивается только 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 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

Ответ 15

используя только классы JRE (System.arraycopy) и пытается свести к минимуму количество объектов temp, которые вы можете напишите что-нибудь вроде:

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

с помощью Collections еще короче:

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

однако мне все еще нравится первая версия.

Ответ 16

Если вы беспокоитесь о скорости, вы должны использовать как можно меньше памяти. Таким образом, требуется работать с массивами символов.

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 и иметь оптимальные результаты.

Ответ 17

Не самый короткий, но (я думаю) самый быстрый способ использовать 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();
  }

Ответ 18

для удобства чтения и переносимости:

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

Ответ 19

Если вас беспокоит производительность, просто используйте StringBuilder внутри цикла и сделайте .toString() при выходе из цикла. Черт, напишите свой собственный класс Util и повторите его использование. 5 Линии кода max.

Ответ 20

Мне очень нравится этот вопрос. Существует много знаний и стилей. Поэтому я не могу оставить его, не показывая свою рок-н-ролл;)

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

Вам нравится?

Ответ 21

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

Ответ 22

Простая петля

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

Ответ 23

Попробуйте следующее:

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

Ответ 24

Используя рекурсию, вы можете сделать следующее (используя тройные операторы, одна строка max):

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

Я знаю, это уродливо и, вероятно, неэффективно, но это одна строка!

Ответ 25

Несмотря на ваше желание не использовать циклы, я думаю, вы должны использовать цикл.

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 не являются хорошими. В ответ на ваши критические замечания:

  • Независимо от того, какое решение вы используете, почти наверняка будет длиннее этого. Использование предварительно созданной функции только замаскирует ее под большим количеством обложек.
  • Кто-то, читающий ваш код, должен будет выяснить, что вы делаете в этом не-for-loop. Учитывая, что for-loop является идиоматическим способом сделать это, было бы намного легче понять, если вы сделали это с циклом for.
  • Да кто-то может добавить что-то умное, но, избегая цикла for, вы делаете что-то умное. Это, как стрелять себе в ногу преднамеренно, чтобы случайно не стрелять в ногу.
  • Ошибки по очереди могут быть легко улавливаемы с помощью одного теста. Учитывая, что вы должны тестировать свой код, следует легко устранить ошибку, которая может быть исправлена ​​и уловлена. И это стоит отметить: в приведенном выше коде не содержится ошибка "один за другим". Для петель одинаково легко получить право.
  • Поэтому не используйте повторно переменные. Это не ошибка для цикла.
  • Опять же, как и любое решение, которое вы используете. И как я уже отмечал; охотник за ошибками, вероятно, ожидает, что вы сделаете это с циклом for, так что им будет легче найти его, если вы используете цикл for.

Ответ 26

вот последняя версия 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 слишком велик, если это небольшой проект

Ответ 28

Так я сделал это без использования цикла:

public class Repeat {

    StringBuilder builder = new StringBuilder();

    public static void main(String[] args) {
        Repeat rep = new Repeat();
        rep.repeat("hello", 10);
        System.out.println(rep.builder);    
    }


    public void repeat(String str, int times){
        if(times == 0){
            return;
        }
        builder.append(str);
        repeat(str, --times);
    }

}

Ответ 29

public static String rep(int a,String k)

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

Вы можете использовать этот рекурсивный метод для достижения желаемой цели.

Ответ 30

repeated = str + str + str;

Иногда просто лучше. Все, кто читает код, могут видеть, что происходит.

И компилятор будет делать причудливые вещи с StringBuilder за кулисами для вас.