자바에서 문자열을 반복하는 간단한 방법


597

나는 String n 번 반복 할 수있는 간단한 commons 메소드 또는 연산자를 찾고 있습니다 . 나는 for 루프를 사용하여 이것을 작성할 수 있다는 것을 알고 있지만 필요할 때마다 for 루프를 피하고 간단한 직접 방법이 어딘가에 있어야합니다.

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

repeated.equals("abcabcabc");

와 연관되다:

문자열 자바 스크립트 반복 주어진 횟수만큼 다른 문자열을 반복하여 NSString 생성

편집

루프가 완전히 필요하지 않은 경우 for 루프를 피하려고합니다.

  1. 그들은 다른 함수에 얽혀 있어도 코드 줄 수에 추가합니다.

  2. 내 코드를 읽는 사람은 for 루프에서 내가하는 일을 알아야합니다. 주석을 달고 의미있는 변수 이름을 가지고 있더라도 여전히 "영리한"작업을 수행하지 않아야합니다.

  3. 프로그래머는 for 루프에 영리한 것을 넣는 것을 좋아합니다. 비록 내가 의도 한 대로만 수행한다고하더라도 누군가가 와서 영리한 "수정"을 추가하는 것을 방해하지는 않습니다.

  4. 그들은 종종 잘못되기 쉽습니다. 인덱스와 관련된 루프는 하나의 버그로 생성되는 경향이 있습니다.

  5. For 루프는 종종 같은 변수를 재사용하므로 범위 지정 버그를 찾기가 매우 어려워집니다.

  6. For 루프는 버그 사냥꾼이 찾아야하는 장소의 수를 늘립니다.


35
for 루프가 실제 문제를 일으킬 수 있음을 이해합니다. 그러나 가독성, 유지 보수성 및 속도가 비싸면 역효과를 낳기 때문에 "모든 비용으로"for 루프를 피하려고 시도해서는 안됩니다. 이것은 그러한 경우 중 하나입니다.
Imagist

9
"그들은 다른 기능을 사용하더라도 코드 줄 수를 늘립니다."와우. LoC가 아닌 Big-O
Pyrolistical

7
@imagist 나는 가독성과 유지 보수 비용이 드는 상황에서 루프를 피하고 있습니다. 나는 여기서 속도를 가장 중요하지 않은 문제로 생각합니다 (사실 비 문제). for 루프가 과도하게 사용되었다고 생각하고 기본 솔루션이 아닌 필요할 때만 루프를 사용하는 방법을 배우려고합니다.
Ethan Heilman

3
@Pyrolistical 나는 성능이나 점근 적 이점을 주장하지 않습니다. 오히려 적은 코드를 작성하고 휠을 재창조하는 대신 라이브러리 함수를 사용하여 가독성을 높이면서 버그 표면 영역 (라인 코드)을 줄입니다. 두 가지 좋은 점 모두 동의 할 것입니다.
Ethan Heilman

4
@ e5; 몇 년 후 게시 해 주셔서 죄송합니다.이 질문이 너무 적절하다고 생각합니다. 메소드에 삽입되면 인수를 테스트하고 (times> = 0) 오류가 발생합니다. 이렇게하면 견고 함과 함께 읽을 수있는 코드 행이 추가됩니다. 문자열을 반복하는 것은 모호하지 않은 일입니다. 누가 주석이나 javadoc 없이도 string.repeat가 수행하는 작업을 정확히 알고있는 코드를 읽는 사람. 안정적인 라이브러리를 사용하면 간단한 함수에는 버그가 없다고 생각하는 것이 합리적입니다. YET은 우리가 걱정해야 할 "견고성"검사의 형태를 소개합니다. 10 가지 개선을 요청할 수 있다면, 이런 것들은 하나 일 것입니다.
AgostinoX

답변:


229

String::repeat

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

Java 11의 새로운 기능은String::repeat 요청한 내용을 정확하게 수행 하는 방법 입니다.

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

자사의 자바 독은 말합니다 :

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


7
나는 거리에서 아직 자바 9를 보지 못했고 ( 오랫 동안 하지 않을 것입니다 .)-그리고 11 은 분명히 선박으로 설정됩니다.
javadba

1
아마도 명백하지만 문자열 리터럴 "abc".repeat(3)
에서도이

895

가장 짧은 버전은 다음과 같습니다 (Java 1.5 이상 필요).

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

n문자열을 반복하려는 횟수는 어디 이며 반복 할 문자열 s입니다.

가져 오기 또는 라이브러리가 필요하지 않습니다.


22
나는 그것이 난독 화되었다고 생각하지 않습니다. 기본 유형 ( char[]이 경우)은 널 (null)로 인스턴스화되고,에서 a String가 작성되고 char[]널 (null)은 replaced()원하는 문자를 사용합니다.s
Amarok

32
이것은 매우 영리하지만 (+1) for 루프가 종종 더 명확한 코드를 만든다는 점을 거의 증명한다고 생각합니다.
Richard Tingle

75
난독 화에 대해 불평하는 사람들에게 가독성은 문해력에 달려 있습니다. 이것은 그것이 무엇을하고 있는지 즉시 알 수없는 사람들을 위해 명확하고 분명합니다. 이것은 Java로 얻는 것입니다.
dansalmo

11
더 나은 성능을 ...replace('\0', str)위해서는 문자열 버전 대신 사용해야합니다.
user686249

11
@ user686249 :이 전용 replace(char oldChar, char newChar)replace(CharSequence target, CharSequence replacement)그래서 나는 그 일을 할 수 표시되지 않습니다
user102008

334

Java <= 7을 사용하는 경우 다음과 같이 "간결"합니다.

// create a string made up of n copies of string s
String.format("%0" + n + "d", 0).replace("0", s);

에서 자바 8 위보다 읽기 쉬운 방법이있다 :

// create a string made up of n copies of string s
String.join("", Collections.nCopies(n, s));

마지막으로 Java 11 이상에서는 repeat​(int count)this ( link )를 위한 새로운 방법이 있습니다.

"abc".repeat(12);

또는 프로젝트에서 Java 라이브러리를 사용하는 경우 더 많은 옵션이 있습니다.

들어 아파치 코 몬즈 :

StringUtils.repeat("abc", 12);

대한 구글 구아바 :

Strings.repeat("abc", 12);

4
전자 n는 0 일 때 예외를 발생시킵니다 .
saka1029

Java 8 예제는 컴파일되지 않습니다-> 형식 불일치 : List <Character>에서 CharSequence로 변환 할 수 없습니다
Arigion

6
@Arigion s은 String이 아니라 String이어야합니다.Char
Caner

@Caner 감사합니다. 내 나쁜, 나는 사과한다. 분명히 나는 ​​어제 너무 피곤했다. downvoting에 대해 죄송합니다. 가능한 한 빨리
공감대를

@Arigion 문제 없음, s가 문자열임을 분명히했습니다
Caner

312

Commons Lang StringUtils.repeat ()

용법:

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

repeated.equals("abcabcabc");

99
장기적으로 단순성을 위해 하나의 방법 의존성을 사용하면 항아리-지옥을 초래할 수 있습니다
dfa

81
물론, 일반적인 랭을 제외하고. 나는 평범한 언어가없는 5000 LOCS 이상의 프로젝트를 본 적이 없다고 생각합니다.
Ethan Heilman

11
Commons Lang은 오픈 소스입니다. 다운로드하여 살펴보십시오. 물론 내부에 루프가 있지만 간단하지는 않습니다. 해당 구현을 프로파일 링하고 최적화하기 위해 많은 노력을 기울였습니다.
ChssPly76

28
성능상의 이유로 루프를 피하지 않습니다 (질문에서 내 이유를 읽으십시오). 누군가 StringUtils.repeat를 보면 내가 무엇을하고 있는지 알고 있습니다. 그들은 내 자신의 반복 버전을 작성하려고 시도하고 실수를했다고 걱정할 필요가 없습니다. 원자인지 단위입니다!
Ethan Heilman

7
@ Thorbjørn Ravn Andersen-상황이 계속 벗어나면 훨씬 더 흥미로워 질 수 있습니다.
ChssPly76

140

Java 8 String.join은 다음과 관련하여 깔끔한 방법을 제공합니다 Collections.nCopies.

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

7
감사합니다! 안드로이드의 경우 String.join () 대신 TextUtils.join ()을 사용할 수 있습니다
MinaHany

2
이 답변에 감사드립니다. 외부 API 주문 유틸리티 방법을 사용하지 않고 가장 깨끗한 방법 인 것 같습니다! 아주 좋아 !!
Andreas M. Oberheim

2
이 방법의 좋은 점은 결합을 사용하면 CSV 목록을 작성하는 경우 매우 편리하게 작동하는 구분 문자를 제공 할 수 있다는 것입니다. 다른 모든 방법을 사용하면 별도의 작업으로 제거 해야하는 종료 결합 문자가 있습니다.
DroidOS

102

표준 String 함수 만 사용하고 명시적인 루프를 사용하지 않는 방법은 다음과 같습니다.

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

5
놀라운 :-) n이 0이되는 것을 조심하십시오…
양 메이어

4
@Vijay Dev & fortran : 아니요 replace(). Java 1.5 이상에서는 replace()두 가지 버전 CharSequence( Strings 포함 )이 필요합니다. download.oracle.com/javase/1.5.0/docs/api/java/lang/…
user102008

79
아야. 이것은 추악합니다.
Karel Bílek

8
@mzuba의 말을 보자 n=3: 그것은 첫째 형식 문자열을 보면 뭔가처럼 %03d(이 %%3 패딩 후 제로, 형식을 추가 할 수있는 서식 코드, 백분율 기호 탈출하는 것) 0로 이어지는, 그와를 000, 그리고 마지막으로 각각 대체 0문자열로를
fortran

15
솔루션을 더보기 흉하고 이해하기 쉽게 만들 수 있습니다. String.format ( "% 0"+ n + "d", 0) .replace ( "0", s)
Artur

87

당신이 나와 같고 Apache Commons가 아닌 Google Guava를 사용하고 싶다면. Guava Strings 클래스에서 repeat 메소드를 사용할 수 있습니다 .

Strings.repeat("-", 60);

2
... 그리고 3Mb의 새로운 의존성을 얻습니다.
MonoThreaded

6
@MonoThreaded 나는 말할 것도없이 갈 것이라고 생각했지만, 문자열 반복을하기 위해 구아바를 포함하지는 않습니다. 내 대답은 어쨌든 구아바를 이미 사용하고 있다면 이것입니다.
Jack

53

을 사용할 수도 있습니다 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());
}

6
... 또는 return IntStream.range(0, times).mapToObj(i -> str).collect(joining());더 나은 병렬 처리
Alexis C.

32

루프를 피하고 싶습니까?

여기 있습니다 :

public static String repeat(String s, int times) {
    if (times <= 0) return "";
    else return s + repeat(s, times-1);
}

(물론 이것은 추악하고 비효율적이지만 루프가 없습니다 :-p)

더 단순하고 예쁘기를 원하십니까? 자이 썬 사용 :

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

두 개의 인수가 필요합니다. 첫 번째는 반복 횟수 (각 함수는 1..n의 반복 시간으로 실행 됨)이고 두 번째는 반복 할 문자열입니다.

지금까지 다른 입력으로 실행되는 시간을 빠르게 검사하면 다음과 같은 순위가 유지됩니다.

  1. 반복적 인 StringBuilder 추가 (1x).
  2. 재귀 연결 log2 호출 (~ 3x).
  3. 재귀 연결 선형 호출 (~ 30x).
  4. 반복 연결 선형 (~ 45x).

재귀 함수가 for루프 보다 빠르다고 추측하지 못했습니다 .

재미있게 보내십시오 (actal xD).


1
재귀 및 명백히 lisp 해커 인 경우 +1 나는 이것이 너무 비효율적이라고 생각하지 않습니다. 문자열 연결은 한 번의 경고가 아닙니다. +는 실제로는 stringBuilder UTH이기 때문입니다. stackoverflow.com/questions/47605/java-string-concatenationschneide.wordpress.com/2009/02/23/…을 참조하십시오 . 나는 그 모든 스택이 재귀 비용에서 얼마나 많이 밀리고 튀어 나오는지 또는 핫스팟이 그것을 돌봐 주는지 궁금합니다. 벤치마킹 할 자유 시간이 있었으면 좋겠다. 다른 사람?
Ethan Heilman

@ e5 : 포트란이 맞다; 이 솔루션을보다 효율적으로 만들 수 있습니다. 이 구현은 각 재귀에 대해 불필요하게 새 StringBuilder (및 새 문자열)를 만듭니다. 그래도 여전히 좋은 해결책입니다.
rob

3
@ e5 Lisp 해커 xD 였으면 좋겠다. 만약 그렇다면, 꼬리 재귀 함수를 사용했을 것이다. :-p
fortran

1
마이크로 벤치 마크는 Java에서 제대로 작동하지 않습니다. 그런 구현 속도를 측정하는 것은 좋지 않습니다.
ceklock

@ tecnotron 알고 있지만 여전히 아무것도 아닌 것보다 낫습니다 ... 그리고 유일한 '놀람'은 순진한 루프 연결과 선형 재귀의 약간의 차이였습니다.
포트란

20

질문보다 문자가 적습니다.

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

4
내 대답 StringUtils.repeat (str, n)보다 많은 문자가 포함되어 있습니다.
Ethan Heilman

8
이미 Apache Commons를 사용하지 않는 한이 답변은 번거 로움이 적습니다. 클래스 경로에 라이브러리를 포함하여 다른 라이브러리를 다운로드하지 않고 라이센스가 귀하의 라이브러리와 호환되는지 확인하십시오.
Paul Tomblin

7
null을 반환하지 마십시오.이 경우 빈 문자열을 반환하여 항상 반환 된 값을 선택하지 않은 상태로 사용할 수 있습니다. 그렇지 않으면 포스터 사용을 권장합니다.
Thorbjørn Ravn Andersen

7
s가 null 인 경우 처리하는 세 가지 방법이 있습니다. 1. 오류를 전달하십시오 (널 리턴). 2. 오류를 숨기십시오 ( ""리턴). 3. NPE를 처리하십시오. 오류를 숨기고 NPE를 던지는 것은 시원하지 않으므로 오류를 전달했습니다.
Pyrolistical

1
@EthanHeilman은 2MB의 가치를 더하고 commons-lang3.3.1-sources더 이상 좋지 않습니다.)하지만 누군가 이미 가지고 있다면 commons-lang, 나는 당신의 대답을지지합니다.
TWiStErRob

9

를 기반으로 포트란의 대답은 , 이것은 모두 StringBuilder를 사용하는 recusive 버전입니다 :

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

1
재귀 대신 루프를 반복하면 많은 반복 횟수에 대한 스택 프레임 수가 줄어 듭니다.
La-comadreja

7

달러를 사용하는 것은 입력하는 것만 큼 간단합니다.

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

추신 : 반복 은 배열, 목록, 설정 등에 대해서도 작동합니다 .


3
assertThat () 메소드가 실제로 필요합니까?
ceklock

7

JDBC 목적으로 쉼표로 구분 된 물음표 목록을 만드는 기능을 원했고이 게시물을 찾았습니다. 그래서 저는 두 가지 변형을 선택하여 어느 것이 더 나은 성능을 발휘하기로 결정했습니다. 백만 번의 반복 후에 정원 다양성 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);
}

3
나는 두 번째 것이 훨씬 오래 걸릴 것이라는 것이 이해됩니다. 문자열 검색을 수행 한 다음 문자열 문자를 문자별로 수정합니다.
Ethan Heilman

7

OOP 솔루션

거의 모든 대답은 솔루션으로 정적 함수를 제안하지만 Object-Oriented (재사용 목적 및 명확성을 위해) 생각하는 CharSequence-Interface (변형 가능한 CharSequence-Classes에 대한 유용성을 열어주는)를 통해 위임을 통해 솔루션을 생각해 냈습니다.

다음 클래스는 Separator-String / CharSequence와 함께 또는없이 사용할 수 있으며 "toString ()"에 대한 각 호출은 최종 반복 문자열을 빌드합니다. Input / Separator는 String-Class로 제한 될뿐만 아니라 CharSequence를 구현하는 모든 Class (예 : 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's 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

4
역겨운 것을 본 적이 거의 없습니다 : /
Ven

6

JRE 클래스 ( System.arraycopy ) 만 사용 하고 다음과 같이 작성할 수있는 임시 객체 수 를 최소화하려고합니다 .

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

컬렉션을 사용하는 것이 훨씬 짧습니다.

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

그러나 나는 여전히 첫 번째 버전을 좋아합니다.


6
-1 : 너무 영리하다. 코드를 읽을 수 있거나 효율적으로 만드는 것이 목표라면 이러한 "솔루션"은 좋은 생각이 아닙니다. '반복'은 StringBuilder를 사용하여 간단히 다시 작성할 수 있습니다 (초기 용량 설정). 그리고 'repeat2'/ 'repeat3'은 실제로 비효율적이며 String []. toString ()에 의해 생성 된 String의 지정되지 않은 구문에 의존합니다.
Stephen C

@Thorb : 절대적으로이 코드를 사용하면 "metacharacter", [],
dfa를

@Stephen : 루프를 명시 적으로 요청 하지 않도록 질문이 편집되었습니다 . StringBuilder 기반 답변이 이미 제공되었으므로 사본을 게시하지 않았습니다.
dfa

@ 스테판 : 나는 downvote를 알아낼 수 없습니다. 편집 한 답변은 반복적으로 루프가 없습니다. 효율성에 대한 요청이 없습니다. 이 질문은 루프없이 연결을 만들기 위한 지적 노력 이라고 생각합니다 .
dfa

@Stephan : Collection.toString (및 Arrays.toString)을 통해 생성 된 문자열은 AbstractCollection.toString에 명확하게 지정 되어 있습니다. "[]"). 인접한 요소는 ","(쉼표 및 공백) 문자로 구분됩니다. "
dfa

6

아니 짧은,하지만 (내가 생각하는) 가장 빠른 방법은 모두 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();
  }

5

속도가 걱정된다면 가능한 한 적은 메모리 복사를 사용해야합니다. 따라서 문자 배열로 작업해야합니다.

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에서 시작하여 최적의 결과를 얻는 것입니다.


4

가독성과 이식성을 위해 :

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

3

성능이 걱정된다면 루프 내부에서 StringBuilder를 사용하고 루프 종료시 .toString ()을 수행하십시오. Util Class를 작성하고 재사용하십시오. 최대 5 줄의 코드


2

나는이 질문을 정말로 즐긴다. 많은 지식과 스타일이 있습니다. 그래서 나는 내 로큰롤을 보여주지 않고 그것을 떠날 수 없다.)

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

당신은 그것을 좋아합니까?


1
보다 극단적 인 테스트에서는 -Xms4937m을 사용하여 1,700,000,000 (1.7 gigas) 문자열 반복 길이를 생성합니다.
Daniel De León

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

2

간단한 루프

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

2
timesStringBuilder 생성자에 전달하십시오 .
Behrouz.M

2

이것을 시도하십시오 :

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

2

재귀를 사용하면 다음을 수행 할 수 있습니다 (삼항 연산자를 사용하여 최대 한 줄).

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

나는 추악하고 아마도 효율적이지 않지만 한 줄입니다!


이것이 내가 취하는 접근법이지만 왜 필요한 것보다 더 많은 검사를합니까? 반환 번호> 0? 문자열 + 반복 (문자열, 숫자 -1) : "";
Fering

아, niczm25가 아래 답변으로 보입니다
Fering

@이 방법은 항상 O (N)보다는 O (log N) 평균이되도록 주된 이유를 제공합니다. 그럼에도 불구하고 여전히 나쁘지만 다른 것보다 약간 더 많은 최적화.
HyperNeutrino

2

간단한 한 줄 솔루션 :
Java 8 필요

Collections.nCopies( 3, "abc" ).stream().collect( Collectors.joining() );

1

루프를 사용하지 않기를 원하지만 루프를 사용해야한다고 생각합니다.

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 루프를 사용하지 않는 이유는 좋지 않습니다. 당신의 비판에 대한 응답으로 :

  1. 어떤 솔루션을 사용하든 거의 이보다 더 길 것입니다. 사전 빌드 된 기능을 사용하면 더 많은 기능을 사용할 수 있습니다.
  2. 코드를 읽는 사람은 비 루프에서 수행중인 작업을 파악해야합니다. for-loop가이를 수행하는 관용적 인 방법이기 때문에 for-loop로 수행했는지 알아내는 것이 훨씬 쉽습니다.
  3. 네 사람이 영리한 뭔가를 추가 할 수 있지만 루프를 피함으로써 수도 당신이 하는 영리한 뭔가를하고 . 그것은 실수로 발로 자신을 쏘지 않도록 의도적으로 발로 자신을 쏘는 것과 같습니다.
  4. 한 번의 테스트로 한 번에 한 가지 오류를 쉽게 파악할 수 있습니다. 코드를 테스트해야한다고 생각하면, 한 번에 하나씩 오류를 수정하고 파악하기 쉬워야합니다. 그리고 주목할 가치가 있습니다. 위의 코드에는 1 개씩의 오류가 없습니다. For 루프는 똑같이 쉽게 얻을 수 있습니다.
  5. 따라서 변수를 재사용하지 마십시오. 그것은 for-loop의 잘못이 아닙니다.
  6. 다시 말하지만 사용하는 모든 솔루션도 마찬가지입니다. 그리고 내가 전에 언급했듯이; 버그 헌터는 아마도 for 루프로 이것을 할 것으로 기대할 것이므로, for 루프를 사용하면 버그를 쉽게 찾을 수 있습니다.

3
-1. 다음은 두 가지 연습 문제입니다. a)로 코드를 실행하십시오 repetitions = -5. b) Commons Lang을 다운로드 repeatString('a', 1000)하고 루프에서 백만 번 실행 ; 코드와 동일하게 수행하십시오. 시간을 비교하십시오. 추가 크레딧의 경우와 동일하게 수행하십시오 repeatString('ab', 1000).
ChssPly76 22

2
그렇다면 코드가 더 읽기 쉽다고 주장하고 StringUtils.repeat("ab",1000)있습니까? 그게 당신이 공감 한 내 대답 이었으니까. 또한 성능이 좋고 버그가 없습니다.
ChssPly76

2
인용하려는 질문에서 두 번째 문장을 읽으십시오. 답장 후 Andrew Hare의 답변에 대한 답변으로 "왜냐하면 모든 비용으로 루프를 피하려고합니다."는 질문에 추가되었습니다. 사용 어디서나 영업 질문에 대한 답변이 없습니다. " dfa의 솔루션조차도 독창적입니다. 내부 루프에 사용됩니다. "jar hell"이 위에 응답되었습니다. commons lang은 어쨌든 모든 크기의 응용 프로그램에서 사용되므로 새로운 종속성을 추가하지 않습니다.
ChssPly76

2
이 시점에서 @ ChssPly76 나는 상상가가 트롤링하고 있다고 확신합니다. 나는 내가 쓴 것을 어떻게 읽을 수 있는지, 위에서 입력 한 답변을 진지하게 생각할 수있는 방법을 보는 것이 정말 힘들다.
Ethan Heilman

1
@ ChssPly76 내 대답에는 전혀 루프가 없습니다 :-p
fortran

1

출력 문자열 의 길이 만 알고 입력 문자열의 길이로 나눌 수없는 경우이 방법을 사용하십시오.

static String repeat(String s, int length) {
    return s.length() >= length ? s.substring(0, length) : repeat(s + s, length);
}

사용 데모 :

for (int i = 0; i < 50; i++)
    System.out.println(repeat("_/‾\\", i));

이 경우 원하는 결과를 얻는 것이 불가능하므로 empty slength> 0 과 함께 사용하지 마십시오 .


0

다음은 최신 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,이 작업을 수행하는 가장 좋은 방법은 위에서 언급 한 코드 또는 여기에 대한 답변을 사용하는 것입니다. 그러나 작은 프로젝트라면 커먼 랭은 너무 커요


나는 당신이 할 수있는 다른 많은 것이 없다고 생각합니다 ... 아마도 AOT!
alexmherrmann

0

나는 당신이 원하는 것과 같은 일을하는 재귀 적 방법을 만들었습니다. 이것을 자유롭게 사용하십시오 ...

public String repeat(String str, int count) {
    return count > 0 ?  repeat(str, count -1) + str: "";
}

난에 같은 대답이 반복 시퀀스에 자바 캔 I 다중 문자열을?


불필요한 문자열 재 할당 및 재귀 오버 헤드 ... 나쁜, 나쁜, 좋지 않은.
알렉산더-복원 모니카

1
느려질 것입니다. 추천하지 않습니다! StringBuilder대신 사용하십시오 .
Svetlin Nakov

0
public static String rep(int a,String k)

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

이 재귀 방법을 원하는 목표에 사용할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.