Создайте строку из n символов

Есть ли способ в java создать строку с указанным номером указанного символа? В моем случае мне нужно было бы создать строку с 10 пробелами. Мой текущий код:

StringBuffer outputBuffer = new StringBuffer(length);
for (int i = 0; i < length; i++){
   outputBuffer.append(" ");
}
return outputBuffer.toString();

Есть ли лучший способ сделать то же самое? В частности, хотелось бы чего-то быстрого (с точки зрения исполнения).


person C. Ross    schedule 10.05.2010    source источник
comment
Если вы обнаружите, что делаете это часто, просто напишите функцию: String characterRepeat (Char c, int Length) {...}, которая делает то же самое, что и вы, для любого символа и любой длины. Тогда просто позвоните, когда вам это нужно.   -  person Austin Fitzpatrick    schedule 10.05.2010
comment
вы хотите использовать StringBuilder вместо StringBuffer   -  person    schedule 10.05.2010
comment
Добавьте вначале размер буфера, это легко вычислить и упростит управление памятью !. StringBuilder outputBuffer = новый StringBuilder (повтор * base.length ());   -  person Victor    schedule 10.01.2015
comment
См. Также: stackoverflow .com / questions / 1235179 /   -  person Dave Jarvis    schedule 13.03.2015
comment
Если вы хотите добавить один пробел, используйте вместо этого append(' ') ... это требует немного меньше вычислений ...   -  person Erk    schedule 06.06.2018
comment
Java 8: Stream и nCopies - stackoverflow.com/a/51925748/1216775   -  person akhil_mittal    schedule 08.10.2018


Ответы (27)


Цикл for будет оптимизирован компилятором. В таких случаях, как ваш, вам не нужно самостоятельно заботиться об оптимизации. Доверьтесь компилятору.

Кстати, если есть способ создать строку с n пробелами, то она закодирована так же, как и вы.

person kalkin    schedule 10.05.2010
comment
даже если это не было оптимизировано - как часто это создается в вашей программе - если часто сохраняется в статической переменной или другом кеше - person mmmmmm; 10.05.2010
comment
btw Array.fill () просто перебирает массив. / мне нужно определенно больше очков, чтобы комментировать посты других :) - person kalkin; 10.05.2010
comment
@Mark Length - переменная, поэтому сохранять ее глупо. Что бы я сделал, если бы у меня был static Dictionary<int, String>? - person C. Ross; 24.05.2010
comment
Сохраните самую длинную строку, которую вы когда-либо захотите, а затем используйте что-то вроде этого: " ".substring(0, 10); - person mjaggard; 06.01.2014

Вероятно, самый короткий код с использованием String API, исключительно:

String space10 = new String(new char[10]).replace('\0', ' ');

System.out.println("[" + space10 + "]");
// prints "[          ]"

В качестве метода без прямого создания экземпляра char:

import java.nio.CharBuffer;

/**
 * Creates a string of spaces that is 'spaces' spaces long.
 *
 * @param spaces The number of spaces to add to the string.
 */
public String spaces( int spaces ) {
  return CharBuffer.allocate( spaces ).toString().replace( '\0', ' ' );
}

Вызвать с помощью:

System.out.printf( "[%s]%n", spaces( 10 ) );
person polygenelubricants    schedule 11.05.2010
comment
Несмотря на то, что мне нравится однострочник, я думаю, что решение FrustratedWithFormsDes лучше, когда дело доходит до выполнения, поскольку оно избегает проверки каждого на \ 0 и просто назначает пространство. - person Bouncner; 17.01.2013
comment
Проверено, это всегда быстрее, чем цикл, довольно последовательно на 50000–100000 наносекунд быстрее, что может быть довольно значительным (0,1 миллисекунды), цикл действительно ускоряется по мере увеличения количества итераций, хотя общее время все еще велико. Это справедливо для создания пробелов разных размеров. - person kmecpp; 08.07.2015
comment
взбейте за довольно красивое решение, я использовал его в своем ответе здесь stackoverflow.com/questions/852665/ - person maytham-ɯɐɥʇʎɐɯ; 13.04.2017

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

Вместо этого повторно используйте одну из доступных библиотек, предоставляющую код, который делает то же самое, например StringUtils.repeatfrom Язык Apache Commons:

StringUtils.repeat(' ', length);

Таким образом, вам также не нужно беспокоиться о производительности, поэтому все кровавые детали StringBuilder, оптимизации компилятора и т. Д. Будут скрыты. Если бы функция оказалась такой медленной, это было бы ошибкой библиотеки.

С Java 11 становится еще проще:

" ".repeat(length);
person mfuchs    schedule 30.07.2014
comment
С другой стороны, если StringUtils еще не используется в проекте, добавление еще одной зависимости для такой простой задачи может оказаться излишним. - person Erich Kitzmueller; 26.04.2018
comment
если он оказался медленным, вы также можете отправить собственное исправление для функции. - person will; 28.08.2018

Хм, теперь, когда я думаю об этом, возможно, _ 1_:

char[] charArray = new char[length];
Arrays.fill(charArray, ' ');
String str = new String(charArray);

Конечно, я предполагаю, что метод fill делает то же самое, что и ваш код, поэтому он, вероятно, будет работать примерно так же, но, по крайней мере, это меньше строк.

person FrustratedWithFormsDesigner    schedule 10.05.2010
comment
После проверки источника кажется, что он действительно делает именно то, что опубликовал OP: строка 806 из docjar.com/html/api/java/util/Arrays.java.html - person Pops; 10.05.2010
comment
@Lord Torgamus Был ли отредактирован вопрос ОП? Потому что в версии, которую я вижу, он зацикливается на StringBuffer.append (), а версия Frustrated выполняет заливку (которая, конечно, циклически выполняет присвоение char массиву). Совсем не одно и то же. - person CPerkins; 11.05.2010
comment
@CPerkins, честно, я не понял. Я хочу сказать, что они оба делают посимвольную вставку внутри цикла for. - person Pops; 11.05.2010
comment
@Lord Torgamus - Согласен с этим. жаль, что jvm не может просто выполнить memset. Цена, которую мы платим за широкие символы. - person CPerkins; 11.05.2010
comment
Кто-нибудь знает, можно ли писать, например. 64-битное длинное значение со значением 0 в строке char (при условии, что мы хотим исправить длину строки до 64/65)? - person Bouncner; 17.01.2013
comment
@Pops, стоит отметить, что если функция Arrays.fill() последовательно используется для выполнения этой работы в коде и (стандартной и внешней) библиотеки, то она является хорошим кандидатом для компиляции Hotspot и лучше шанс найти кеш вашего процессора. Будущие JVM могут назначить его как внутреннюю функцию. Самостоятельное катание отрезает вас от всей этой безупречной производительности ... - person SusanW; 05.08.2016

В Java 8 вы можете использовать String.join:

String.join("", Collections.nCopies(n, s));
person Vitalii Fedorenko    schedule 25.03.2017

начиная с Java 11:

" ".repeat(10);

начиная с Java 8:

generate(() -> " ").limit(10).collect(joining());

где:

import static java.util.stream.Collectors.joining;
import static java.util.stream.Stream.generate;
person epox    schedule 15.08.2019

Если вам нужны только пробелы, то как насчет:

String spaces = (n==0)?"":String.format("%"+n+"s", "");

что приведет к появлению пробелов abs (n);

person BryceCicada    schedule 15.08.2012
comment
А как это по скорости? У меня такое впечатление, что формат относительно медленный. Он должен проанализировать строку, прежде чем сможет ее создать. - person C. Ross; 15.08.2012

Начиная с Java 11, вы можете просто использовать _ 1_, чтобы решить вашу проблему.

Возвращает строку, значение которой является объединением этой строки, повторенной count раз.

Если эта строка пуста или count равно нулю, возвращается пустая строка.

Таким образом, вместо цикла ваш код будет выглядеть так:

" ".repeat(length);
person Samuel Philipp    schedule 07.06.2019

Я думаю, что это меньше кода, чем возможно, он использует класс Guava Joiner:

Столяр .on (""). join (Collections.nCopies (10, ""));

person meilechh    schedule 13.02.2014
comment
Самая короткая строка кода, но добавление большой библиотеки только для этой простой задачи не имеет смысла. Я могу создать JAR меньшего размера с помощью одного метода pubic String n(int n) { ... }, который позволит использовать еще меньше кода: n(10), но опять же, это не имеет никакого смысла. - person isapir; 03.01.2018
comment
@isapir Это отличный ответ для людей, которые уже используют Guava. - person nasch; 27.06.2018
comment
@nasch Guava не входил в вопрос. Но в любом случае в 2018 году действительно нет причин использовать Guava Joiner, когда вы можете использовать String.join (), который был добавлен в Java 8. См. stackoverflow.com/a/43011939/968244 - person isapir; 27.06.2018
comment
@isapir Нет, Гуава был ответом. Ответы на StackOverflow имеют более широкую аудиторию, чем просто человек, задающий вопрос, поэтому нормально, если некоторые ответы не являются лучшими для человека, задающего вопрос. И комментарий о String.join () отличный, хотя я не уверен, доступен ли он во всех версиях Android, что широко используется в Java. - person nasch; 27.06.2018

Вы можете использовать стандартную функцию String.format для генерации N пробелов. Например:

String.format("%5c", ' ');

Делает строку с 5 пробелами.

or

int count = 15;
String fifteenSpacebars = String.format("%" + count + "c", ' ');

Делает строку из 15 пробелов.

Если вы хотите, чтобы повторялся другой символ, вы должны заменить пробелы желаемым символом:

int count = 7;
char mySymbol = '#';
System.out.println(String.format("%" + count + "c", ' ').replaceAll("\\ ", "\\" + mySymbol));

Вывод:

#######
person Alexey Gusev    schedule 25.07.2018

Мой вклад основан на алгоритме быстрого возведения в степень.

/**
 * Repeats the given {@link String} n times.
 * 
 * @param str
 *            the {@link String} to repeat.
 * @param n
 *            the repetition count.
 * @throws IllegalArgumentException
 *             when the given repetition count is smaller than zero.
 * @return the given {@link String} repeated n times.
 */
public static String repeat(String str, int n) {
    if (n < 0)
        throw new IllegalArgumentException(
                "the given repetition count is smaller than zero!");
    else if (n == 0)
        return "";
    else if (n == 1)
        return str;
    else if (n % 2 == 0) {
        String s = repeat(str, n / 2);
        return s.concat(s);
    } else
        return str.concat(repeat(str, n - 1));
}

Я протестировал алгоритм против двух других подходов:

  • Обычный цикл for с использованием String.concat() для объединения строки
  • Обычный цикл for с использованием StringBuilder

Тестовый код (конкатенация с использованием цикла for и String.concat() становится слишком медленной для больших n, поэтому я оставил его после 5-й итерации).

/**
 * Test the string concatenation operation.
 * 
 * @param args
 */
public static void main(String[] args) {
    long startTime;
    String str = " ";

    int n = 1;
    for (int j = 0; j < 9; ++j) {
        n *= 10;
        System.out.format("Performing test with n=%d\n", n);

        startTime = System.currentTimeMillis();
        StringUtil.repeat(str, n);
        System.out
                .format("\tStringUtil.repeat() concatenation performed in    %d milliseconds\n",
                        System.currentTimeMillis() - startTime);

        if (j <5) {
            startTime = System.currentTimeMillis();
            String string = "";
            for (int i = 0; i < n; ++i)
                string = string.concat(str);
            System.out
                    .format("\tString.concat() concatenation performed in        %d milliseconds\n",
                            System.currentTimeMillis() - startTime);
        } else
            System.out
                    .format("\tString.concat() concatenation performed in        x milliseconds\n");
        startTime = System.currentTimeMillis();
        StringBuilder b = new StringBuilder();
        for (int i = 0; i < n; ++i)
            b.append(str);
        b.toString();
        System.out
                .format("\tStringBuilder.append() concatenation performed in %d milliseconds\n",
                        System.currentTimeMillis() - startTime);
    }
}

Результаты:

Performing test with n=10
    StringUtil.repeat() concatenation performed in    0 milliseconds
    String.concat() concatenation performed in        0 milliseconds
    StringBuilder.append() concatenation performed in 0 milliseconds
Performing test with n=100
    StringUtil.repeat() concatenation performed in    0 milliseconds
    String.concat() concatenation performed in        1 milliseconds
    StringBuilder.append() concatenation performed in 0 milliseconds
Performing test with n=1000
    StringUtil.repeat() concatenation performed in    0 milliseconds
    String.concat() concatenation performed in        1 milliseconds
    StringBuilder.append() concatenation performed in 1 milliseconds
Performing test with n=10000
    StringUtil.repeat() concatenation performed in    0 milliseconds
    String.concat() concatenation performed in        43 milliseconds
    StringBuilder.append() concatenation performed in 5 milliseconds
Performing test with n=100000
    StringUtil.repeat() concatenation performed in    0 milliseconds
    String.concat() concatenation performed in        1579 milliseconds
    StringBuilder.append() concatenation performed in 1 milliseconds
Performing test with n=1000000
    StringUtil.repeat() concatenation performed in    0 milliseconds
    String.concat() concatenation performed in        x milliseconds
    StringBuilder.append() concatenation performed in 10 milliseconds
Performing test with n=10000000
    StringUtil.repeat() concatenation performed in    7 milliseconds
    String.concat() concatenation performed in        x milliseconds
    StringBuilder.append() concatenation performed in 112 milliseconds
Performing test with n=100000000
    StringUtil.repeat() concatenation performed in    80 milliseconds
    String.concat() concatenation performed in        x milliseconds
    StringBuilder.append() concatenation performed in 1107 milliseconds
Performing test with n=1000000000
    StringUtil.repeat() concatenation performed in    1372 milliseconds
    String.concat() concatenation performed in        x milliseconds
    StringBuilder.append() concatenation performed in 12125 milliseconds

Вывод:

  • Для больших n - используйте рекурсивный подход
  • Для малых n - для цикла достаточная скорость
person Niels Billen    schedule 06.01.2015
comment
Это интересная реализация. К сожалению, вопреки вашим выводам, при больших n это очень неэффективно. Я подозреваю, что это из-за того, что каждый раз, когда вы объединяете строки, происходит выделение большого количества памяти. Попробуйте написать его как оболочку вокруг рекурсивного метода, который принимает StringBuilder вместо String. Бьюсь об заклад, вы обнаружите, что результаты будут намного лучше. - person Klitos Kyriacou; 30.01.2015
comment
Есть много мер предосторожности, которые вы должны предпринять при микротестировании чего-то вроде этого, и я не думаю, что вы принимаете какие-либо из них! Основными вопросами производительности этого кода могут быть следующие: скомпилирован ли он с помощью Hotspot, сколько мусора он создает и т. Д. Готов поспорить, что все эти операторы if испортят прогноз ветвления ЦП. Это действительно должно быть переделано с помощью JMH (openjdk.java.net/projects/code-tools / jmh), иначе бессмысленно. - person SusanW; 05.08.2016
comment
Обратите внимание, что эта реализация имеет сложность O (n * log n), а StringBuilder - O (n) :) - person Leo Leontev; 09.06.2019

Как насчет этого?

char[] bytes = new char[length];
Arrays.fill(bytes, ' ');
String str = new String(bytes);
person Martijn Courteaux    schedule 10.05.2010
comment
Это то же самое, что и существующий ответ - person Krease; 18.04.2017

Учитывая, что у нас есть:

String c = "c"; // character to repeat, for empty it would be " ";
int n = 4; // number of times to repeat
String EMPTY_STRING = ""; // empty string (can be put in utility class)

Java 8 (с использованием потока)

String resultOne = IntStream.range(0,n)
   .mapToObj(i->c).collect(Collectors.joining(EMPTY_STRING)); // cccc

Java 8 (с использованием nCopies)

String resultTwo = String.join(EMPTY_STRING, Collections.nCopies(n, c)); //cccc
person akhil_mittal    schedule 20.08.2018
comment
Collectors.joining(EMPTY_STRING) эквивалентно Collectors.joining() - person PPartisan; 26.06.2019

RandomStringUtils имеет положение для создания строки из заданного размера ввода. Не могу прокомментировать скорость, но это один лайнер.

RandomStringUtils.random(5,"\t");

создает вывод

\t\t\t\t\t

предпочтительно, если вы не хотите видеть в своем коде \ 0.

person Mulki    schedule 02.05.2016

Используйте StringUtils: StringUtils.repeat ('', 10)

person Icegras    schedule 07.02.2019

Кратчайшее решение с Guava:

Strings.repeat(" ", len)

С помощью Простой способ повторить строку в java.

person Vadzim    schedule 08.09.2019

Это сработало для меня без использования каких-либо внешних библиотек в Java 8

String sampleText = "test"
int n = 3;
String output = String.join("", Collections.nCopies(n, sampleText));
System.out.println(output);

И на выходе

testtesttest
person Sajan John    schedule 04.01.2020

int c = 10; Строковые пробелы = String.format ("%" + c + "c", ''); это решит вашу проблему.

person Mr.Geeky    schedule 04.01.2020

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

person Andreas Dolk    schedule 10.05.2010

Просто замените свой StringBuffer на StringBuilder. Трудно превзойти это.

Если у вас большая длина, вы можете реализовать более эффективное (но более неуклюжее) самодобавление, дублируя длину на каждой итерации:

 public static String dummyString(char c, int len) {
  if( len < 1 ) return "";
  StringBuilder sb = new StringBuilder(len).append(c);
  int remnant = len - sb.length();
  while(remnant  > 0) {
   if( remnant  >= sb.length() ) sb.append(sb);
   else sb.append(sb.subSequence(0, remnant));
   remnant  = len - sb.length();
  }
  return sb.toString();
 }

Кроме того, вы можете попробовать Arrays.fill() aproach (ответ FrustratedWithFormsDesigner).

person leonbloy    schedule 10.05.2010
comment
Можете ли вы назвать некоторые переменные более чем одним символом? - person C. Ross; 11.05.2010

Вы можете заменить StringBuffer на StringBuilder (последний не синхронизируется, может быть быстрее в однопоточном приложении)

И вы можете создать экземпляр StringBuilder один раз, вместо того, чтобы создавать его каждый раз, когда он вам нужен.

Что-то вроде этого:

class BuildString {
     private final StringBuilder builder = new StringBuilder();
     public String stringOf( char c , int times ) {

         for( int i = 0 ; i < times ; i++  ) {
             builder.append( c );
         }
         String result = builder.toString();
         builder.delete( 0 , builder.length() -1 );
         return result;
      }

  }

И используйте это так:

 BuildString createA = new BuildString();
 String empty = createA.stringOf( ' ', 10 );

Если вы используете свой createA как переменную экземпляра, вы можете сэкономить время на создании экземпляров.

Это не потокобезопасно, если у вас несколько потоков, у каждого потока должна быть собственная копия.

person OscarRyz    schedule 10.05.2010

Для хорошей производительности объедините ответы из aznilamir и из FrustratedWithFormsDesigner

private static final String BLANKS = "                       ";
private static String getBlankLine( int length )
{
    if( length <= BLANKS.length() )
    {
        return BLANKS.substring( 0, length );
    }
    else
    {
        char[] array = new char[ length ];
        Arrays.fill( array, ' ' );
        return new String( array );
    }
}

Отрегулируйте размер BLANKS в зависимости от ваших требований. Моя конкретная строка BLANKS имеет длину около 200 символов.

person oHo    schedule 25.04.2014

У вас есть такой метод. Это добавляет необходимые пробелы в конце заданного String, чтобы заданный String имел длину определенной длины.

public static String fillSpaces (String str) {

    // the spaces string should contain spaces exceeding the max needed
    String spaces = "                                                   ";
    return str + spaces.substring(str.length());
}
person Anil    schedule 08.08.2014

Хотите, чтобы строка имела фиксированный размер, поэтому вы либо заполняете, либо усекаете для табулирования данных ...

class Playground {
    private static String fixStrSize(String s, int n) {
        return String.format("%-" + n + "s", String.format("%." + n +"s", s));
    }

    public static void main(String[ ] args) {
        System.out.println("|"+fixStrSize("Hell",8)+"|");
        System.out.println("|"+fixStrSize("Hells Bells Java Smells",8)+"|");
    }
}

|Hell    |
|Hells Be|

Отличная ссылка здесь.

person JGFMK    schedule 02.01.2020

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

public static String padString(String str, int leng,char chr) {
        for (int i = str.length(); i <= leng; i++)
            str += chr;
        return str;
    }
person Yashpal Singla    schedule 21.03.2013
comment
Это существенно медленнее. - person SLaks; 28.05.2013
comment
Вы можете использовать StringBuffer вместо конкатенации строк, если строки, с которыми вы имеете дело, имеют большой размер. Это значительно повлияет на скорость - person Yashpal Singla; 29.05.2013

как насчет этого?

public String fillSpaces(int len) {
    /* the spaces string should contain spaces exceeding the max needed */  
    String spaces = "                                                   ";
    return spaces.substring(0,len);
}

РЕДАКТИРОВАТЬ: Я написал простой код для проверки концепции и вот что я нашел.

Метод 1: добавление одного пробела в цикл:

  public String execLoopSingleSpace(int len){
    StringBuilder sb = new StringBuilder();

    for(int i=0; i < len; i++) {
        sb.append(' ');
    }

    return sb.toString();
  }

Метод 2: добавьте 100 пробелов и зациклите, затем подстроку:

  public String execLoopHundredSpaces(int len){
    StringBuilder sb = new StringBuilder("          ")
            .append("          ").append("          ").append("          ")
            .append("          ").append("          ").append("          ")
            .append("          ").append("          ").append("          ");

    for (int i=0; i < len/100 ; i++) {
        sb.append("          ")
            .append("          ").append("          ").append("          ")
            .append("          ").append("          ").append("          ")
            .append("          ").append("          ").append("          ");
    }

    return sb.toString().substring(0,len);
  }

В результате я получаю 12 345 678 пробелов:

C:\docs\Projects> java FillSpace 12345678
method 1: append single spaces for 12345678 times. Time taken is **234ms**. Length of String is 12345678
method 2: append 100 spaces for 123456 times. Time taken is **141ms**. Length of String is 12345678
Process java exited with code 0

и для 10 000 000 мест:

C:\docs\Projects> java FillSpace 10000000
method 1: append single spaces for 10000000 times. Time taken is **157ms**. Length of String is 10000000
method 2: append 100 spaces for 100000 times. Time taken is **109ms**. Length of String is 10000000
Process java exited with code 0

сочетание прямого выделения и итерации всегда занимает меньше времени, в среднем на 60 мс меньше при создании огромных пространств. Для меньших размеров оба результата незначительны.

Но продолжайте комментировать :-)

person aznilamir    schedule 03.04.2012
comment
@ aznilamir: Хм, а как у тебя дела с 10к пробелов? - person Jayan; 03.04.2012
comment
Идея состоит в том, чтобы объединить петлевое и прямое выделение 100 мест. Вот фрагменты кода: - person aznilamir; 07.04.2012
comment
Почему вы используете несколько добавлений для добавления 100 символов? Почему не добавить один 100 символов? - person nycynik; 17.08.2016

Я не знаю встроенного метода того, о чем вы спрашиваете. Однако для небольшой фиксированной длины, такой как 10, ваш метод должен быть достаточно быстрым.

person Pops    schedule 10.05.2010
comment
Если бы только это была небольшая фиксированная длина вроде 10. - person C. Ross; 11.05.2010