Create a string with n characters
Asked Answered
M

27

189

Is there a way in Java to create a string with a specified number of a specified character? In my case, I would need to create a string with ten spaces. My current code is:

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

Is there a better way to accomplish the same thing? In particular, I'd like something that is fast (in terms of execution).

Malignancy answered 10/5, 2010 at 17:21 Comment(6)
If you find yourself doing it a lot, just write a function: String characterRepeat(Char c, int Length){ ... } which does what you do there for any character and any length. Then just call it when you need it.Disinclination
you want to use StringBuilder instead of StringBufferSidra
Add at the beggining the size of the buffer, is easy to calculate an facilitates things in memory managemnt!. StringBuilder outputBuffer = new StringBuilder(repeat * base.length());Bechuana
See also: #1235679Dagnydago
If you want to append a single space, use append(' ') instead... it involves a little bit less computing...Poisson
Java 8 : Stream and nCopies - https://mcmap.net/q/103090/-create-a-string-with-n-charactersCalamitous
D
42

The for loop will be optimized by the compiler. In such cases like yours you don't need to care about optimization on your own. Trust the compiler.

BTW, if there is a way to create a string with n space characters, than it's coded the same way like you just did.

Demarco answered 10/5, 2010 at 17:25 Comment(4)
even if this was not optimised - how often is this created in your program - if often save in a static variable or other cacheFeigned
btw Array.fill() just loops through the array. /me need definitively more points to comment on others posts :)Demarco
@Mark Length is variable, so it seems silly to save it. What would I do, have a static Dictionary<int, String>?Malignancy
Store the longest you'll ever want the string, then use something like this: " ".substring(0, 10);Volney
A
195

Likely the shortest code using the String API, exclusively:

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

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

As a method, without directly instantiating 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 using:

System.out.printf( "[%s]%n", spaces( 10 ) );
Antho answered 11/5, 2010 at 2:35 Comment(3)
Even though I like the one-liner, I think FrustratedWithFormsDes's solution is the better when it comes to execution since it avoids checking each for \0 and simply assigns the space.Fleck
Tested, this is always faster than the loop, pretty consistently 50000-100000 nano seconds faster, which could be pretty significant (0.1 milliseconds) the loop does get faster as the number of iterations increases although the total time is still high. This holds true for when creating different sizes of space strings.Adanadana
thump up for pretty nice solution, I have used it in my answer here #853165Fortification
C
96

I highly suggest not to write the loop by hand. You will do that over and over again during the course of your programming career. People reading your code - that includes you - always have to invest time, even if it are just some seconds, to digest the meaning of the loop.

Instead reuse one of the available libraries providing code that does just that like StringUtils.repeatfrom Apache Commons Lang:

StringUtils.repeat(' ', length);

That way you also do not have to bother about performance, thus all the gory details of StringBuilder, Compiler optimisations etc. are hidden. If the function would turn out as slow it would be a bug of the library.

With Java 11 it becomes even easier:

" ".repeat(length);
Cr answered 30/7, 2014 at 20:51 Comment(2)
On the other hand, if StringUtils is not already used in the project, adding yet another dependency for such a simple task might be an overkill.Ralleigh
if it turned-out slow you can also submit your own fix for the function.Bilinear
S
77

Hmm now that I think about it, maybe Arrays.fill:

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

Of course, I assume that the fill method does the same thing as your code, so it will probably perform about the same, but at least this is fewer lines.

Samford answered 10/5, 2010 at 17:26 Comment(6)
After checking the source, it seems that this does in fact do exactly what the OP posted: line 806 of docjar.com/html/api/java/util/Arrays.java.htmlCarolann
@Lord Torgamus Was the OP's question edited? Because in the version I see, he's looping on StringBuffer.append(), and Frustrated's version is doing a fill (which of course loops doing char assignments to the array). Not the same thing at all.Midwife
@CPerkins, fair enough, I wasn't clear. My point is that both of them do a character-by-character insertion inside of a for loop.Carolann
@Lord Torgamus - Agreed on that. pity the jvm can't just do a memset. Price we pay for wide characters.Midwife
Does anyone know if it's possible to write e.g. a 64-bit long value with the value 0 into the char string (assuming we want to fix the String length to 64/65)?Fleck
@Carolann it's worth noting that if the Arrays.fill() function is used consistently for doing this job across your code and (standard and external) library code, then it makes a good candidate for Hotspot compilation, and stands a better chance of being found your CPU cache. Future JVMs may assign it as an intrinsic function. Rolling your own cuts you off from all this performance goodness...Comradery
E
64

since Java 11:

" ".repeat(10);

since Java 8:

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

where:

import static java.util.stream.Collectors.joining;
import static java.util.stream.Stream.generate;
Estragon answered 15/8, 2019 at 18:42 Comment(2)
Wish Java could learn from Python here.. Something like System.out.println("="*10);Ionium
@Ionium I feel like "=".repeat(10) is close enough to "=" * 10 here. It's more explicit / less error prone (For example '=' * 10 in python is '==========' but in java is 610) and it's not that much longer.Mustachio
D
42

The for loop will be optimized by the compiler. In such cases like yours you don't need to care about optimization on your own. Trust the compiler.

BTW, if there is a way to create a string with n space characters, than it's coded the same way like you just did.

Demarco answered 10/5, 2010 at 17:25 Comment(4)
even if this was not optimised - how often is this created in your program - if often save in a static variable or other cacheFeigned
btw Array.fill() just loops through the array. /me need definitively more points to comment on others posts :)Demarco
@Mark Length is variable, so it seems silly to save it. What would I do, have a static Dictionary<int, String>?Malignancy
Store the longest you'll ever want the string, then use something like this: " ".substring(0, 10);Volney
V
31

In Java 8 you can use String.join:

String.join("", Collections.nCopies(n, s));
Vase answered 25/3, 2017 at 2:40 Comment(0)
Z
14

If you want only spaces, then how about:

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

which will result in abs(n) spaces;

Zima answered 15/8, 2012 at 10:37 Comment(1)
How is that for speed though? I'm under the impression format is relatively slow. It has to parse the string before it can create it after all.Malignancy
L
14

Since Java 11 you can simply use String.repeat(count) to solve your problem.

Returns a string whose value is the concatenation of this string repeated count times.

If this string is empty or count is zero then the empty string is returned.

So instead of a loop your code would just look like this:

" ".repeat(length);
Lien answered 7/6, 2019 at 10:12 Comment(0)
H
8

I think this is the less code it's possible, it uses Guava Joiner class:

Joiner.on("").join(Collections.nCopies(10, " "));

Historicism answered 13/2, 2014 at 17:41 Comment(4)
The shortest line of code but adding a large library just for that simple task doesn't make sense. I can create a smaller JAR myself with a single method pubic String n(int n) { ... } which will allow even "less" code: n(10), but again, doesn't make any sense.Shayne
@Shayne This is a great answer for people who are already using GuavaSurra
@Surra Guava wasn't part of the question. But anyway, in 2018 there is really no reason to use Guava's Joiner when you can use String.join() which was added in Java 8. See https://mcmap.net/q/103090/-create-a-string-with-n-charactersShayne
@Shayne No, Guava was an answer. Answers on StackOverflow have a wider audience than just the person asking the question, so it's fine if some answers aren't the best for the person asking. And the comment about String.join() is a great one though I'm not sure if it's available on all versions of Android, which is a prominent use of Java.Surra
M
8

You can use standard String.format function for generate N spaces. For example:

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

Makes a string with 5 spaces.

or

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

Makes a string of 15 spacebars.

If you want another symbol to repeat, you must replace spaces with your desired symbol:

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

Output:

#######
Magnoliamagnoliaceous answered 25/7, 2018 at 22:28 Comment(0)
F
6

My contribution based on the algorithm for fast exponentiation.

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

I tested the algorithm against two other approaches:

  • Regular for loop using String.concat() to concatenate string
  • Regular for loop using a StringBuilder

Test code (concatenation using a for loop and String.concat() becomes to slow for large n, so I left it out after the 5th iteration).

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

Results:

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

Conclusion:

  • For large n - use the recursive approach
  • For small n - for loop has sufficient speed
Franklyn answered 6/1, 2015 at 10:23 Comment(3)
This is an interesting implementation. Unfortunately, contrary to your conclusions, it is very inefficient for large n. I suspect this is because of the many memory allocations that are going on every time you concatenate strings. Try writing it as a wrapper around a recursive method that takes StringBuilder instead of String. I bet you'll find the results will be much better.Riant
There are lots of precautions you need to take when micro-benchmarking something like this, and I don't think you are taking any of them! The dominant performance questions around this code could easily be whether it is Hotspot-compiled, how much garbage it creates, etc. I bet all those if statements are going to mess up the CPU's branch prediction. This should really be redone using JMH (openjdk.java.net/projects/code-tools/jmh), otherwise it's a bit pointless.Comradery
Note that this implementation has O(n * log n) complexity, while StringBuilder is O(n) :)Fogarty
M
4

How about this?

char[] bytes = new char[length];
Arrays.fill(bytes, ' ');
String str = new String(bytes);
Merryman answered 10/5, 2010 at 18:31 Comment(1)
This is same as this existing answerHeraclid
C
4

Considering we have:

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 (Using Stream)

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

Java 8 (Using nCopies)

String resultTwo = String.join(EMPTY_STRING, Collections.nCopies(n, c)); //cccc
Calamitous answered 20/8, 2018 at 7:17 Comment(1)
Collectors.joining(EMPTY_STRING) is equivalent to Collectors.joining()Frijol
R
3

Use StringUtils: StringUtils.repeat(' ', 10)

Royce answered 7/2, 2019 at 16:6 Comment(0)
H
3

The shortest solution with Guava:

Strings.repeat(" ", len)

Via Simple way to repeat a String in java.

Holpen answered 8/9, 2019 at 13:48 Comment(0)
M
3

This worked out for me without using any external libraries in Java 8

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

And the output is

testtesttest
Mercurialize answered 4/1, 2020 at 14:48 Comment(0)
B
2

RandomStringUtils has a provision to create a string from given input size. Cant comment on the speed, but its a one liner.

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

creates an output

\t\t\t\t\t

preferable if you dont want to see \0 in your code.

Bowshot answered 2/5, 2016 at 8:7 Comment(0)
T
2

int c = 10; String spaces = String.format("%" +c+ "c", ' '); this will solve your problem.

Tacit answered 4/1, 2020 at 15:14 Comment(0)
L
1

In most cases you only need Strings upto a certains length, say 100 spaces. You could prepare an array of Strings where the index number is equal to the size of the space-filled string and lookup the string, if the required length is within the limits or create it on demand if it's outside the boundary.

Lefthander answered 10/5, 2010 at 18:15 Comment(0)
H
1

For good performance, combine answers from aznilamir and from 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 );
    }
}

Adjust size of BLANKS depending on your requirements. My specific BLANKS string is about 200 characters length.

Haplite answered 25/4, 2014 at 16:52 Comment(1)
I like your idea, it's not much pretty, but very clever.Allina
N
0

Just replace your StringBuffer with a StringBuilder. Hard to beat that.

If your length is a big number, you might implement some more efficient (but more clumsy) self-appendding, duplicating the length in each iteration:

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

Also, you might try the Arrays.fill() aproach (FrustratedWithFormsDesigner's answer).

Neile answered 10/5, 2010 at 17:39 Comment(1)
Can you name some of the variables more than one character?Malignancy
J
0

You can replace StringBuffer with StringBuilder ( the latter is not synchronized, may be a faster in a single thread app )

And you can create the StringBuilder instance once, instead of creating it each time you need it.

Something like this:

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

  }

And use it like this:

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

If you hold your createA as a instance variable, you may save time creating instances.

This is not thread safe, if you have multi threads, each thread should have its own copy.

Jesusitajet answered 10/5, 2010 at 17:48 Comment(0)
R
0

Have a method like this. This appends required spaces at the end of the given String to make a given String to length of specific length.

public static String fillSpaces (String str) {

    // the spaces string should contain spaces exceeding the max needed
    String spaces = "                                                   ";
    return str + spaces.substring(str.length());
}
Ruderal answered 8/8, 2014 at 19:42 Comment(0)
I
0

Want String to be of fixed size, so you either pad or truncate, for tabulating data...

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|

Excellent reference here.

Ionium answered 2/1, 2020 at 21:23 Comment(0)
C
-1

A simple method like below can also be used

public static String padString(String str, int leng,char chr) {
        for (int i = str.length(); i <= leng; i++)
            str += chr;
        return str;
    }
Cockneyfy answered 21/3, 2013 at 18:11 Comment(2)
This is subsantially slower.Kohler
You can use StringBuffer instead of string concatenation, in case the strings you are dealing with are of large size. That will impact the speed considerablyCockneyfy
B
-2

how about this?

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

EDIT: I've written a simple code to test the concept and here what i found.

Method 1: adding single space in a loop:

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

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

    return sb.toString();
  }

Method 2: append 100 spaces and loop, then substring:

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

The result I get creating 12,345,678 spaces:

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

and for 10,000,000 spaces:

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

combining direct allocation and iteration always takes less time, on average 60ms less when creating huge spaces. For smaller sizes, both results are negligible.

But please continue to comment :-)

Blasphemous answered 3/4, 2012 at 8:34 Comment(3)
@ aznilamir : Hm, how will you do for 10k spaces?Sturtevant
The idea is to combine loop and direct allocation of 100 spaces. Here is the code snippets:Blasphemous
Why do you use multiple appends to add 100 characters? Why not one 100 char append?Halfhearted
C
-3

I know of no built-in method for what you're asking about. However, for a small fixed length like 10, your method should be plenty fast.

Carolann answered 10/5, 2010 at 17:25 Comment(1)
If only it was a small fixed length like 10.Malignancy

© 2022 - 2024 — McMap. All rights reserved.