2010-05-10 5 views
93

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

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

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

+1

Если вы обнаружили, что делаете это много, просто написать функцию: String characterRepeat (Char C, внутр длина) {...}, который делает то, что вы сделайте это для любого символа и любой длины. Тогда просто позвоните, когда вам это нужно. –

+6

вы хотите использовать StringBuilder вместо StringBuffer –

+0

Добавить в начале размер буфера, легко вычислить, облегчает работу в управлении памятью !. StringBuilder outputBuffer = new StringBuilder (repeat * base.length()); – Victor

ответ

25

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

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

+1

, даже если это не было оптимизировано - как часто это создается в вашей программе - если часто сохранение в статической переменной или в другом кеше – Mark

+0

btw Array.fill() просто перебирает массив. /Мне нужно окончательно больше очков, чтобы прокомментировать другие сообщения :) – kalkin

+0

@Mark Length - переменная, поэтому кажется глупым ее сохранить. Что бы я сделал, статичный словарь '? –

-3

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

+0

Если бы это была небольшая фиксированная длина, например 10. –

49

Хмм теперь, когда я думаю об этом, может быть, Arrays.fill:

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

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

+2

После проверки источника кажется, что это действительно делает именно то, что опубликовано в OP: строка 806 http://www.docjar.com/html/api/java/util/Arrays.java.html – Pops

+2

@Lord Torgamus Was вопрос OP отредактирован? Потому что в версии, которую я вижу, он зацикливается на StringBuffer.append(), а версия Frustrated выполняет заливку (которая, конечно же, делает циклы для присвоения char массиву). Совсем не то же самое. – CPerkins

+0

@CPerkins, справедливо, я не был ясен. Моя точка зрения заключается в том, что оба они выполняют поэтапную вставку внутри цикла for. – Pops

0

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

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

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() ПОДХОД (РазочарованныйWithFormsDesigner ответ).

+0

Можете ли вы назвать некоторые переменные более одного символа? –

0

Вы можете заменить 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 как переменную экземпляра, вы можете сэкономить время создания экземпляров.

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

0

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

3

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

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

Это похоже на [этот существующий ответ] (http://stackoverflow.com/a/2804866/836214) – Krease

129

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

Invoke с помощью:

System.out.printf("[%s]%n", spaces(10)); 
+4

Несмотря на то, что мне нравится однострочный шрифт, я думаю, что решение FrustratedWithFormsDes лучше, когда дело доходит до исполнения, поскольку оно позволяет избежать проверяя каждый для \ 0 и просто присваивая пробел. – Bouncner

+1

Протестировано, это всегда быстрее, чем цикл, довольно последовательно на 50000-100000 nano секунд быстрее, что может быть довольно значительным (0,1 миллисекунды), цикл становится быстрее по мере увеличения количества итераций, хотя общее время все еще велико. Это справедливо для создания различных размеров пространственных строк. – kmecpp

+0

Thump up для довольно приятного решения, я использовал его в своем ответе здесь http://stackoverflow.com/questions/852665/command-line-progress-bar-in-java/43381186#43381186 –

-2

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

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

EDIT: Я написал простой код для проверки концепции и вот что нашел.

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

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

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

    return sb.toString(); 
    } 

Способ 2: Append 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 мс при создании огромных пространств. Для меньших размеров оба результата незначительны.

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

+3

@ aznilamir: Хм, как вы сделаете для 10k пробелов? – Jayan

+0

Идея состоит в объединении цикла и прямого выделения из 100 пробелов. Вот фрагменты кода: – aznilamir

+0

Почему вы используете несколько приложений для добавления 100 символов? Почему не добавляется 100 символов? – nycynik

8

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

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

, что приведет к абс (п) пространства;

+4

Как это для скорости? У меня формат показов относительно медленный. Он должен разбирать строку, прежде чем она сможет ее создать. –

-1

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

public static String padString(String str, int leng,char chr) { 
     for (int i = str.length(); i <= leng; i++) 
      str += chr; 
     return str; 
    } 
+0

Это подсеанно медленнее. – SLaks

+0

Вы можете использовать StringBuffer вместо конкатенации строк, если строки, с которыми вы имеете дело, имеют большой размер. Это значительно повлияет на скорость –

7

Я думаю, что это меньше кода, это возможно, он использует гуавы Столяр класс:

Joiner .На («»). join (Collections.nCopies (10, ""));

+0

Самая короткая строка кода, но добавление большой библиотеки только для этой простой задачи не имеет смысла.Я могу создать меньший JAR самостоятельно с помощью одного метода 'pubic String n (int n) {...}', который позволит даже «меньше» кода: 'n (10)', но опять же, не имеет никакого смысла , – isapir

0

Для хорошей работы, объединить ответы от 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 символов.

44

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

Вместо повторное один из доступных библиотек, обеспечивающих код, который делает именно это, как StringUtils.repeat из Apache Commons Lang:

return StringUtils.repeat(' ', length); 

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

0

Имейте способ. Это добавляет требуемые пробелы в конце заданного 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()); 
} 
5

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

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

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

  • Regular для цикла с использованием String.concat() конкатенировать снабжать струной, тетивой и т.п.
  • Regular для цикла с использованием кода Test StringBuilder

(конкатенация с использованием a для цикла и 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 - для цикла имеет достаточную скорость
+3

Это интересная реализация. К сожалению, вопреки вашим выводам, это очень неэффективно для больших n. Я подозреваю, что это связано с множеством распределений памяти, которые происходят каждый раз при объединении строк. Попробуйте написать его как обертку вокруг рекурсивного метода, который принимает StringBuilder вместо String. Бьюсь об заклад, вы обнаружите, что результаты будут намного лучше. –

+1

Есть много предосторожностей, которые вам нужно предпринять, когда микро-бенчмаркинг что-то вроде этого, и я не думаю, что вы принимаете какие-либо из них! Доминирующие вопросы производительности вокруг этого кода могут быть легко связаны с компиляцией Hotspot, количеством мусора, который он создает, и т. Д. Я уверен, что все эти утверждения 'if' будут испортить предсказание ветки процессора. Это действительно нужно переделать с помощью JMH (http://openjdk.java.net/projects/code-tools/jmh/), иначе это немного бессмысленно. – SusanW

0

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

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

создает выходной

\ т \ т \ т \ т \ т

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

9

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

String.join("", Collections.nCopies(n, s)); 
Смежные вопросы