StringBuilder의 마지막 문자를 제거 하시겠습니까?


422

컬렉션을 반복하고 구분 기호로 구분 된 각 데이터의 문자열을 만들어야하는 경우 항상 끝에 추가 구분 기호가 있어야합니다. 예 :

for (String serverId : serverIds) {
  sb.append(serverId);
   sb.append(",");
}

같은 것을 제공합니다 : serverId_1, serverId_2, serverId_3,

StringBuilder에서 마지막 문자를 삭제하고 싶습니다 (이 루프 후에 여전히 문자가 필요하기 때문에 변환하지 않고).


11
문자열을 결합하여 "문자열 연결"을 의미하는 경우 문자열 수와 길이에 따라 다릅니다. 문자열이 불변이므로 크기에 관계없이 많은 문자열을 망치려고 할 경우 문자열 빌더를 사용하는 것이 더 효율적입니다. 문자열을 함께 연결할 때마다 새로운 결과 문자열을 생성합니다 (실제로는 문자 배열 임). 문자열 빌더는 본질적으로 toString () 메소드를 호출 할 때까지 변경할 수없는 문자열이 아닌 char 목록입니다.
dyslexicanaboko

4
자바 (8)을 사용하는 경우, 바로 사용 StringJoiner: stackoverflow.com/a/29169233/901641
ArtOfWarfare

답변:


640

다른 사람들은이 deleteCharAt방법 을 지적 했지만 여기에 다른 대안이 있습니다.

String prefix = "";
for (String serverId : serverIds) {
  sb.append(prefix);
  prefix = ",";
  sb.append(serverId);
}

또는 구아바Joiner클래스를 사용하십시오. :)

Java 8 StringJoiner부터는 표준 JRE의 일부입니다.


7
@Coronatus : 아니, "때문에"는 것입니다 없는 모든 문자의 아닌 하나의 문자.
Jon Skeet

31
prefix = ",";를 실행하지 않습니다. 모든 루프 사이클이 성능에 영향을 줍니까?
Harish

21
@Harish : 아마도 작고 작은 비트 일 것입니다. 그러나 그다지 중요하지는 않습니다.
Jon Skeet

4
@Harish-옵티마이 저가 첫 번째 루프 반복을 풀면 전혀 가능하지 않습니다.
Stephen C

6
아파치 커먼즈 구아바이야에 다른 대안을 가지고 Joiner자신의 너무 StringUtils. commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/... , java.lang.String의)
GoRoS

419

또 다른 간단한 해결책은 다음과 같습니다.

sb.setLength(sb.length() - 1);

더 복잡한 해결책 :

위의 해결책은 sb.length() > 0... "마지막으로 제거 할 문자"가 있다고 가정합니다 . 해당 가정을 할 수 없거나 가정이 잘못된 경우 발생할 수있는 예외를 처리 할 수없는 경우 먼저 StringBuilder의 길이를 확인하십시오. 예 :

// Readable version
if (sb.length() > 0) {
   sb.setLength(sb.length() - 1);
}

또는

// Concise but harder-to-read version of the above.
sb.setLength(Math.max(sb.length() - 1, 0));

23
아주 좋은 해결책. 성능에 미치는 영향을 최소화하고 코드를 최소화해야합니다. :)
Alain O'Dea

186
if(sb.length() > 0){
    sb.deleteCharAt(sb.length() - 1);
}

33
이것은 너무 많이 상향 조정되었지만 비효율적이며 system.arraycopy를 수행합니다. @Rohit Reddy Korrapolu가 말한 것.
alianos-

13
그것은 sb.length() == 0또한 안전하지 않습니다
Matthias

대리 쌍 캐릭터가 플레이 할 때 안전한가요?
rogerdpack

마지막 문자가 (예에 따라) 쉼표 구분 기호라고 가정하면 서로 게이트는 아무런 차이가 없습니다. 일반화해야하는 경우 separator.length()1 대신에 빼십시오 .
Stephen C

61

Java 8부터 String 클래스에는 정적 메소드가 join있습니다. 첫 번째 인수는 각 문자열 쌍 사이에서 원하는 문자열이고 두 번째 인수는 Iterable<CharSequence>(두 인터페이스 모두 List<String>작동 하므로 작동하는 것과 같습니다 . 따라서 다음과 같이 할 수 있습니다.

String.join(",", serverIds);

또한 Java 8에서는 StringJoiner전체 요소 목록을 작성하기 전에 문자열 구성을 시작하려는 시나리오에 새 클래스를 사용할 수 있습니다 .


마음에 들지 않으면 nvm이 편집되었습니다. 또한 내 의견도 제거되었습니다.
Eugene

@ Eugene- String.join대신에 초점을 맞추기 위해 답을 완전히 다시 작성했습니다 StringJoiner.
ArtOfWarfare

37

마지막 문자 발생 위치를 얻으십시오.

for(String serverId : serverIds) {
 sb.append(serverId);
 sb.append(",");
}
sb.deleteCharAt(sb.lastIndexOf(","));

때문에 lastIndexOf역 검색을 수행하고, 당신이 첫 번째 시도에서 찾을 수 있음을 알 수, 성능은 여기에 문제가되지 않을 것입니다.

편집하다

내 대답에 계속 관심을 기울이기 때문에 (감사합니다 😊), 그에 관한 가치가 있습니다.

자바 8 이후를 그냥 더 읽기 쉽고 사용이 명시 될 것 StringJoiner을 . 간단한 구분 기호에 대한 한 가지 방법과 접두사 및 접미사에 대한 과부하가 있습니다.

여기에서 가져온 예 :

간단한 구분 기호를 사용하는 예 :

    StringJoiner mystring = new StringJoiner("-");    

    // Joining multiple strings by using add() method  
    mystring.add("Logan");  
    mystring.add("Magneto");  
    mystring.add("Rogue");  
    mystring.add("Storm");  

    System.out.println(mystring);

산출:

로건 마그네토 도적 폭풍

접미사와 접두사가있는 예 :

    StringJoiner mystring = new StringJoiner(",", "(", ")");    

    // Joining multiple strings by using add() method  
    mystring.add("Negan");  
    mystring.add("Rick");  
    mystring.add("Maggie");  
    mystring.add("Daryl");  

    System.out.println(mystring);

산출

(네간, 릭, 매기, 대릴)


마지막 문자는 ,의 마지막 명령문이므로 마지막 문자는 확실 합니다 for loop. 은 lastInfexOf더 읽기 쉽도록하고 0 인덱스인지 아닌지 당신이 기억하고 싶지 않은 경우 생각할 필요도없는 확인하는 것입니다. 또한 stringbuilder 길이에 방해가 될 필요가 없습니다. 그것은 단지 편의를위한 것입니다.
Reuel Ribeiro

34

이 경우

sb.setLength(sb.length() - 1);

'\0'마지막 문자를 삭제 하는 대신 마지막 값을 지정하기 때문에 바람직합니다.System.arraycopy


1
setLength호출은 마지막 값에 아무것도 지정되지 않습니다. Java 문자열 버퍼가 널 (null) / 0으로 종료되지 않았습니다. 실제로 setLength단순히 length필드 를 업데이트하는 것 입니다.
Stephen C

@Rohit Reddy Korrapolu : 그러나 arraycopy사본 0 요소이므로 최적화 할 수 있다고 생각합니다.
maaartinus

2
newLength 인수가 현재 길이보다 크거나 같은 경우 길이가 newLength 인수가되도록 충분한 널 문자 ( '\ u0000')가 추가됩니다. 그렇지 않습니다.
fglez


11

다른 대안

for(String serverId : serverIds) {
   sb.append(",");
   sb.append(serverId); 
}
sb.deleteCharAt(0);

2
크기 계산이 필요하므로 마지막 문자를 제거하는 것보다 낫습니다. 첫 번째 문자를 제거하지 않으면 데이터가 이동하지 않는 한 ...
slott

8

또는

StringBuilder result = new StringBuilder();
for(String string : collection) {
    result.append(string);
    result.append(',');
}
return result.substring(0, result.length() - 1) ;

"."를 추가 할 수 있으므로 사용 가능 끝에.
artfullyConveved

6
StringBuilder sb = new StringBuilder();
sb.append("abcdef");
sb.deleteCharAt(sb.length() - 1);
assertEquals("abcde",sb.toString());
// true

5

또 다른 대안 :

public String join(Collection<String> collection, String seperator) {
    if (collection.isEmpty()) return "";

    Iterator<String> iter = collection.iterator();
    StringBuilder sb = new StringBuilder(iter.next());
    while (iter.hasNext()) {
        sb.append(seperator);
        sb.append(iter.next());
    }

    return sb.toString();
}

3

prefixTextUtils.isEmpty 사용의 재 초기 (성능에 영향)를 피하려면 :

            String prefix = "";
            for (String item : list) {
                sb.append(prefix);
                if (TextUtils.isEmpty(prefix))
                    prefix = ",";
                sb.append(item);
            }

TestUtils는 어떤 종류의 패키지에 속합니까?
Markus

@Markus android.text.TextUtils
NickUnuchek

1

생성 된 텍스트에서 마지막 문자를 제거하는 대신 'Joiner'클래스를 사용하려고 할 수 있습니다.

                List<String> textList = new ArrayList<>();
                textList.add("text1");
                textList.add("text2");
                textList.add("text3");

                Joiner joiner = Joiner.on(",").useForNull("null");
                String output = joiner.join(textList);

               //output : "text1,text2,text3"

1

나는 아래와 같은 일을하고있다 :

    StringBuilder stringBuilder = new StringBuilder();
    for (int i = 0; i < value.length; i++) {
        stringBuilder.append(values[i]);
        if (value.length-1) {
            stringBuilder.append(", ");
        }
    }

0

또 다른 해결책은 다음과 같습니다.

for(String serverId : serverIds) {
   sb.append(",");
   sb.append(serverId); 
}

String resultingString = "";
if ( sb.length() > 1 ) {
    resultingString = sb.substring(1);
}

1
아 ... 알겠습니다. StringBuilder에서 문자열이 아닌 하위 문자열을 호출하고 있습니다.
Stephen C

그러나 어쨌든 이것은 2010 년부터 Zaki 솔루션의 작은 변형 일뿐입니다.
Stephen C

0

나는 개인적으로 끝에 백 스페이스 문자 (또는 더 긴 "구분 기호")를 추가하고 싶습니다.

for(String serverId : serverIds) {
    sb.append(serverId);
    sb.append(",");
}

sb.append('\b');

문제가 있음을 참고하십시오.

  • \b표시되는 방법 은 환경에 따라 다릅니다.
  • length()String내용은 "공개 대상"문자의 길이가 다를 수 있습니다

\b외모 확인과 길이가 같은 콘솔에 로그인으로 중요하지 않습니다, 이것은 나에게 충분한 것 같다.


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