n 개의 문자로 문자열 만들기


144

Java에서 지정된 수의 지정된 문자로 문자열을 만드는 방법이 있습니까? 필자의 경우 공백이 10 개인 문자열을 만들어야합니다. 내 현재 코드는 다음과 같습니다

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

같은 것을 성취하는 더 좋은 방법이 있습니까? 특히 나는 (실행 측면에서) 빠른 것을 원합니다.


1
자신이 많은 일을하는 것을 발견하면 다음과 같은 함수를 작성하십시오. 그런 다음 필요할 때 전화하십시오.
오스틴 피츠 패트릭

12
StringBuffer 대신 StringBuilder를 사용하려고합니다

버퍼의 크기를 시작하면서 추가 할 수 있으며, 메모리 관리가 용이 ​​해집니다!. StringBuilder outputBuffer = 새로운 StringBuilder (repeat * base.length ());
Victor


단일 공간을 추가하려면 append(' ')대신 사용하십시오. 컴퓨팅이 조금 덜 필요합니다.
Erk

답변:


36

for 루프는 컴파일러에 의해 최적화됩니다. 당신과 같은 경우에는 스스로 최적화 할 필요가 없습니다. 컴파일러를 신뢰하십시오.

BTW, n 개의 공백 문자로 문자열을 만드는 방법이 있다면 방금했던 것과 같은 방식으로 코딩됩니다.


1
이것이 최적화되지 않았더라도-프로그램에서 얼마나 자주 생성되는지-정적 변수 또는 다른 캐시에 저장되는 경우
mmmmmm

btw Array.fill ()은 배열을 반복합니다. / me 다른 게시물에 댓글을 달려면 확실히 더 많은 포인트가 필요합니다 :)
kalkin

@Mark Length는 가변적이므로 저장하는 것이 어리석은 것 같습니다. 내가 무엇을해야 static Dictionary<int, String>합니까?
C. Ross

1
문자열을 원할 때 가장 길게 저장 한 후 다음과 같이 사용하십시오. " ".substring(0, 10);
mjaggard

169

StringAPI를 사용하는 가장 짧은 코드는 다음과 같습니다.

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

4
하나의 라이너를 좋아하지만 FrustratedWithFormsDes의 솔루션은 \ 0에 대해 각각을 검사하지 않고 단순히 공간을 할당하기 때문에 실행과 관련하여 더 낫습니다.
Bouncner

1
테스트 한 결과 루프보다 항상 빠르며 50000-100000 나노 초 더 빠릅니다. 총 시간이 여전히 높지만 반복 횟수가 증가함에 따라 루프가 훨씬 빨라질 수 있습니다 (0.1 밀리 초). 다른 크기의 공간 문자열을 만들 때도 마찬가지입니다.
kmecpp

꽤 좋은 솔루션을 쿵, 여기 내 대답에 그것을 사용했다 stackoverflow.com/questions/852665/...
maytham-ɯɐɥʇʎɐɯ

66

흠 이제 내가 생각할 것입니다 Arrays.fill.

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

물론, fill메소드가 코드와 동일한 작업을 수행 한다고 가정 하므로 아마도 거의 동일하게 수행되지만 최소한 줄 수는 적습니다.


2
소스를 확인한 후에는 실제로 OP가 게시 한 내용과 정확히 일치하는 것 같습니다. docjar.com/html/api/java/util/Arrays.java.html의
Pops

2
@Lord Torgamus OP의 질문이 편집 되었습니까? 내가 본 버전에서, 그는 StringBuffer.append ()에서 루핑하고 있으며, Frustrated의 버전은 채우기를 수행하고 있습니다 (물론 배열에 대한 문자 할당을 반복합니다). 전혀 같은 것이 아닙니다.
CPerkins

@ CPerkins, 충분히 공정한, 나는 명확하지 않았다. 내 요점은 둘 다 for 루프 내에서 문자별로 삽입하는 것입니다.
Pops

1
@로드 Torgamus-그것에 동의했다. 유감스럽게도 jvm은 memset을 수행 할 수 없습니다. 넓은 문자에 대해 지불하는 가격입니다.
CPerkins

2
@Pops Arrays.fill()코드 (표준 및 외부) 라이브러리 코드 에서이 작업을 수행하기 위해 함수가 일관되게 사용 되면 핫스팟 컴파일의 좋은 후보가되고 CPU 캐시를 찾을 가능성이 높아집니다. 향후 JVM은이를 고유 함수 로 지정할 수 있습니다. 자신을
굴리면

65

나는 루프를 손으로 쓰지 말 것을 강력히 권합니다. 당신은 프로그래밍 경력 동안 반복해서 그렇게 할 것입니다. 코드를 읽는 사람들은-당신을 포함하여-루프의 의미를 소화하기 위해 몇 초 만에 시간을 투자해야합니다.

대신 재사용 만 수행하는 코드를 제공하는 사용 가능한 라이브러리 중 하나 같은 StringUtils.repeat에서 아파치 코 몬즈 랭 :

StringUtils.repeat(' ', length);

그렇게하면 성능에 신경 쓰지 않아도되므로 StringBuilder컴파일러 최적화 등 의 모든 세부 사항 이 숨겨집니다. 함수가 느리게 나오면 라이브러리의 버그 일 것입니다.

자바 (11) 가 더 쉽게된다 :

" ".repeat(length);

5
반면에 StringUtils가 프로젝트에서 아직 사용되지 않은 경우 이러한 간단한 작업에 대한 또 다른 종속성을 추가하는 것은 과도한 작업 일 수 있습니다.
Erich Kitzmueller

1
속도가 느리면 기능에 대한 수정 사항을 제출할 수도 있습니다.
됩니다


13

공백 만 원하면 어떻습니까?

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

abs (n) 공백이 발생합니다.


6
속도는 어떻습니까? 노출 형식이 비교적 느립니다. 결국 문자열을 구문 분석해야합니다.
C. Ross

11

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;

9

Java 11부터는 간단히 String.repeat(count)문제를 해결하는 데 사용할 수 있습니다.

이 문자열을 반복해서 연결 한 값을 가진 문자열을 반환합니다 count.

이 문자열이 비어 있거나 count0이면 빈 문자열이 반환됩니다.

따라서 루프 대신 코드는 다음과 같습니다.

" ".repeat(length);

8

나는 이것이 가능한 코드가 아니라고 생각하고 Guava Joiner 클래스를 사용합니다.

결합 자 .on ( ""). join ( Collections.nCopies (10, ""));


가장 짧은 코드 줄이지 만 간단한 작업을 위해 큰 라이브러리를 추가하는 것은 의미가 없습니다. pubic String n(int n) { ... }"더 적은"코드를 허용 하는 단일 메소드 를 사용하여 더 작은 JAR을 직접 작성할 수 있습니다 . n(10)그러나 다시 말이되지 않습니다.
isapir

@isapir 이것은 이미 구아바를 사용하는 사람들에게 훌륭한 답변입니다
nasch

1
@nasch Guava는 질문의 일부가 아닙니다. 그러나 어쨌든 2018 년에 Java 8에 추가 된 String.join ()을 사용할 수있을 때 Guava의 Joiner를 사용할 이유가 실제로 없습니다. stackoverflow.com/a/43011939/968244
isapir

@isapir 아니요, 구아바가 답이었습니다. StackOverflow에 대한 답변은 질문을하는 사람보다 더 많은 청중을 갖습니다. 따라서 일부 답변이 요청하는 사람에게 적합하지 않은 경우에 좋습니다. 그리고 String.join ()에 대한 의견은 훌륭한 버전이지만 모든 Android 버전에서 사용할 수 있는지 잘 모르겠습니다. 이는 Java를 많이 사용합니다.
nasch

7

String.formatN 개의 공간을 생성 하기 위해 표준 기능을 사용할 수 있습니다 . 예를 들면 다음과 같습니다.

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

공백이 5 개인 문자열을 만듭니다.

또는

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

15 개의 스페이스 바 문자열을 만듭니다.

다른 기호를 반복하려면 공백을 원하는 기호로 바꿔야합니다.

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

산출:

#######

6

빠른 지수화 알고리즘을 기반으로 한 나의 기여.

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

다른 두 가지 접근 방식에 대해 알고리즘을 테스트했습니다.

  • String.concat()문자열을 연결 하는 데 사용 되는 정규 for 루프
  • a를 사용하여 규칙적인 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-재귀 접근법을 사용하십시오.
  • 작은 nfor 루프의 속도는 충분합니다

4
이것은 흥미로운 구현입니다. 불행히도, 당신의 결론과 달리, 그것은 큰 n에 대해 매우 비효율적입니다. 나는 이것이 문자열을 연결할 때마다 진행되는 많은 메모리 할당 때문이라고 생각합니다. String 대신 StringBuilder를 사용하는 재귀 메서드 주위에 래퍼로 ​​작성하십시오. 결과가 훨씬 나아질 것입니다.
Klitos Kyriacou

3
이와 같은 마이크로 벤치마킹을 할 때주의해야 할 사항이 많이 있습니다. 이 코드의 주된 성능 문제는 핫스팟으로 컴파일되었는지, 얼마나 많은 가비지를 생성하는지 등입니다. 모든 if문장이 CPU의 분기 예측을 망칠 것이라고 확신합니다 . JMH ( openjdk.java.net/projects/code-tools/jmh )를 사용하여 실제로 다시 작성해야합니다 . 그렇지 않으면 조금 의미가 없습니다.
SusanW

이 구현은 O (n * log n) 복잡성을 가지지 만 StringBuilder는 O (n) :)
Leo Leontev


4

우리는 다음을 고려합니다.

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

1
Collectors.joining(EMPTY_STRING)에 해당합니다Collectors.joining()
PPartisan

2

RandomStringUtils 에는 주어진 입력 크기에서 문자열을 작성하는 규정이 있습니다. 캔 트는 속도에 대해 언급하지만 하나의 라이너입니다.

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

출력을 만듭니다

\ t \ t \ t \ t \ t

코드에서 \ 0 을보고 싶지 않으면 선호됩니다 .



1

대부분의 경우 문자열은 특정 길이까지만 필요합니다 (예 : 100 칸). 인덱스 번호가 공백으로 채워진 문자열의 크기와 같은 문자열 배열을 준비하고 필요한 길이가 한계 내에 있거나 문자열이 경계를 벗어나면 필요에 따라 문자열을 조회 할 수 있습니다.



0

그냥 당신의 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 의 답변)를 시도 할 수 있습니다 .


변수의 이름을 둘 이상의 문자로 지정할 수 있습니까?
C. Ross

0

당신은 대체 할 수 StringBufferStringBuilder(후자가 동기화되지, 더 빠른 단일 스레드 응용 프로그램에서 할 수있다)

또한 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

좋은 성능을 위해 aznilamirFrustratedWithFormsDesigner의 답변을 결합하십시오.

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 자입니다.


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

0

데이터 크기를 조정하기 위해 문자열 크기를 고정 시키려면 패딩 또는 자르기를 원합니다 ...

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|

여기에 훌륭한 참조 .


0

이것은 Java 8에서 외부 라이브러리를 사용하지 않고 나를 위해 해결되었습니다.

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

그리고 출력은

testtesttest

0

int c = 10; 문자열 공간 = String.format ( "%"+ c + "c", ''); 이렇게하면 문제가 해결됩니다.


-1

아래와 같은 간단한 방법도 사용할 수 있습니다

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

이것은 상당히 느립니다.
SLaks

처리하는 문자열의 크기가 큰 경우 문자열 연결 대신 StringBuffer를 사용할 수 있습니다. 그것은 속도에 상당한 영향을 미칠 것입니다
Yashpal Singla

-2

이건 어때요?

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

직접 할당과 반복을 결합하면 큰 공간을 만들 때 항상 평균 60ms 더 적은 시간이 걸립니다. 작은 크기의 경우 두 결과 모두 무시할 수 있습니다.

그러나 의견을 계속하십시오 :-)


3
@ aznilamir : 흠, 당신은 어떻게 10k 공간을 위해 할 것입니까?
Jayan

아이디어는 100 개의 공간을 루프와 직접 할당하는 것입니다. 다음은 코드 스 니펫입니다.
aznilamir

여러 개의 추가 기능을 사용하여 100자를 추가하는 이유는 무엇입니까? 왜 100 개의 문자가 추가되지 않습니까?
nycynik

-3

나는 당신이 요구하는 것에 대한 내장 방법이 없다는 것을 알고 있습니다. 그러나 10과 같은 작은 고정 길이의 경우 방법이 훨씬 빠릅니다.


만약 그것이 10과 같은 작은 고정 길이라면
C. Ross
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.