stringbuilder로 빌드 된 문자열에서 마지막 문자를 제거하는 가장 좋은 방법


92

나는 다음이있다

data.AppendFormat("{0},",dataToAppend);

이것의 문제는 내가 루프에서 사용하고 있고 시험용 쉼표가 있다는 것입니다. 후행 쉼표를 제거하는 가장 좋은 방법은 무엇입니까?

데이터를 문자열 하위 문자열로 변경해야합니까?


10
string.Join(",", yourCollection)? 편집 : 답변으로 추가되었습니다.
Vlad


@Chris : 이렇게하면 StringBuilder가 전혀 필요하지 않습니다.
Vlad

나중에 제거하는 대신 쉼표를 추가하는 것을 피할 수 있습니다. 참조 : stackoverflow.com/questions/581448/... (존 소총의 대답)
파올로 팔라 벨라

@Vlad 그래 미안해, 나는 그것을 잘못 읽었다; 나는 당신이 그의 루프를 완전히 대체하는 것이 아니라 최종적으로 만들어진 문자열을 변경하라는 제안으로 제안했다고 생각했습니다. (내가 알아 맞추기, 시간 내 댓글을 삭제 생각!)
크리스 싱클레어

답변:


223

가장 간단하고 효율적인 방법 은 다음 명령을 수행하는 입니다.

data.Length--;

이렇게하면 포인터 (예 : 마지막 인덱스)를 한 문자 뒤로 이동하지만 개체의 변경 가능성은 변경하지 않습니다. 사실, a를 지우는 StringBuilder것도 가장 좋은 방법입니다 Length(그러나 실제로 Clear()구현이보기 때문에 명확성을 위해 메서드를 사용하십시오 ).

data.Length = 0;

다시 말하지만 할당 테이블을 변경하지 않기 때문입니다. 이 바이트를 더 이상 인식하고 싶지 않다고 생각하십시오. 이제를 호출 ToString()할 때도을 (를) 지나는 것을 인식 Length하지 못합니다. 그것은 당신이 제공하는 것보다 더 많은 공간을 할당하는 변경 가능한 객체이며, 단순히 이런 방식으로 구축되었습니다.


2
re data.Length = 0;: 정확히하는 StringBuilder.Clear일이므로 StringBuilder.Clear의도의 명확성을 위해 사용 하는 것이 좋습니다 .
Eren Ersönmez 2013-06-20

@ ErenErsönmez, 공평한 친구, 그게 무슨 일인지 더 분명하게 말 했어야 Clear()했지만 재미있는 일입니다. 이것이 방법 의 첫 번째 줄 입니다 Clear(). 그러나 인터페이스가 실제로 return this;. 이제 그게 나를 죽이는 것입니다. Length = 0변경 사항을 이미 가지고있는 참조로 설정하는 이유는 무엇입니까?
Mike Perrenoud 2013-06-20

12
"유창한"방식으로 사용할 수있는 것이라고 생각합니다. Append자신도 반환합니다.
Eren Ersönmez 2013-06-20

43

그냥 사용

string.Join(",", yourCollection)

이렇게하면 StringBuilder및 루프 가 필요하지 않습니다 .




비동기 케이스에 대한 긴 추가. 2019 년에는 데이터가 비동기 적으로 들어오는 경우가 드물지 않습니다.

데이터가 비동기 수집에있는 경우에는이 없습니다 string.Join과부하 복용 IAsyncEnumerable<T>. 그러나 다음에서 코드를string.Join 해킹 하여 수동으로 생성하는 것은 쉽습니다 .

public static class StringEx
{
    public static async Task<string> JoinAsync<T>(string separator, IAsyncEnumerable<T> seq)
    {
        if (seq == null)
            throw new ArgumentNullException(nameof(seq));

        await using (var en = seq.GetAsyncEnumerator())
        {
            if (!await en.MoveNextAsync())
                return string.Empty;

            string firstString = en.Current?.ToString();

            if (!await en.MoveNextAsync())
                return firstString ?? string.Empty;

            // Null separator and values are handled by the StringBuilder
            var sb = new StringBuilder(256);
            sb.Append(firstString);

            do
            {
                var currentValue = en.Current;
                sb.Append(separator);
                if (currentValue != null)
                    sb.Append(currentValue);
            }
            while (await en.MoveNextAsync());
            return sb.ToString();
        }
    }
}

데이터가 비동기 적으로오고 있지만 인터페이스 IAsyncEnumerable<T>가 지원되지 않는 경우 (주석에서 언급 한 것처럼 SqlDataReader) 데이터를 다음으로 래핑하는 것이 상대적으로 쉽습니다 IAsyncEnumerable<T>.

async IAsyncEnumerable<(object first, object second, object product)> ExtractData(
        SqlDataReader reader)
{
    while (await reader.ReadAsync())
        yield return (reader[0], reader[1], reader[2]);
}

그리고 그것을 사용하십시오 :

Task<string> Stringify(SqlDataReader reader) =>
    StringEx.JoinAsync(
        ", ",
        ExtractData(reader).Select(x => $"{x.first} * {x.second} = {x.product}"));

사용하려면 Select, 당신은 nuget 패키지를 사용해야합니다 System.Interactive.Async. 여기 에서 컴파일 가능한 예제를 찾을 수 있습니다.


12
가장 좋은 대답은 문제를 해결하는 것이 아니라이를 방지하는 것입니다.
LastTribunal

1
@Seabizkit : 물론입니다! 그런데 전체 질문은 C #에 관한 것입니다.
Vlad

1
@Vlad 나는 원시 테스트와 같은 간단한 테스트를 수행하고 있으며 동일하게 생성하지 않았기 때문에 두 번 확인했습니다. string.Join(",", yourCollection)여전히 ,끝에 있습니다. 따라서 위의 즉, string.Join(",", yourCollection)비효율적이며 스스로 제거하지 않습니다.
Seabizkit

2
@Seabizkit : 아주 이상합니다! 예제를 게시 할 수 있습니까? 내 코드에서는 완벽하게 작동합니다 : ideone.com/aj8PWR
Vlad

2
수년 동안 루프를 사용하여 문자열 작성기를 만든 다음 후행 쉼표를 제거하면 이것을 사용할 수 있습니다. 팁 고마워!
Caverman

11

루프 후에 다음을 사용하십시오.

.TrimEnd(',')

또는 단순히 변경

string commaSeparatedList = input.Aggregate((a, x) => a + ", " + x)

4
그는 문자열이 아닌 StringBuilder를 사용하고 있습니다. 더욱이 그것은 매우 비효율적입니다. 먼저 문자열로 변환 한 다음 트리밍합니다.
Piotr Stapp 2013 년

또는string.Join(",", input)
Tvde1

11

이건 어때..

string str = "The quick brown fox jumps over the lazy dog,";
StringBuilder sb = new StringBuilder(str);
sb.Remove(str.Length - 1, 1);

7

나는 stringbuilder의 길이를 조작하는 것을 선호합니다.

data.Length = data.Length - 1;

4
왜 단순히 data.Length--또는 --data.Length?
Gone Coding

나는 보통 data.Length를 사용하지만 한 경우에는 제거하려는 문자 뒤에 공백 값이 있기 때문에 2 자 뒤로 이동해야했습니다. 이 경우 트림도 작동하지 않았으므로 data.Length = data.Length-2; 일했다.
Caverman

트림 반환 문자열의 새로운 인스턴스, 그것은 모두 StringBuilder 객체의 내용을 변경하지 않습니다
bastos.sergio

@GoneCoding은 Visual Basic .NET은 지원하지 않습니다 --또는 ++ 당신은 사용할 수 data.Length -= 1있지만, 또는이 답변도 작동합니다.
Jason S

3

루프 알고리즘을 변경하는 것이 좋습니다.

  • 항목 뒤가 아니라 앞에 쉼표를 추가하십시오.
  • false로 시작하는 부울 변수를 사용하고 첫 번째 쉼표를 억제하십시오.
  • 테스트 후이 부울 변수를 true로 설정하십시오.

2
이것은 아마도 모든 제안 중 가장 효율이 낮고 더 많은 코드가 필요합니다.
Gone Coding

1
@Vlad 대답을보세요
Noctis

3

string.Join메서드를 사용하여 항목 모음을 쉼표로 구분 된 문자열로 바꿔야 합니다. 선행 또는 후행 쉼표가 없는지 확인하고 문자열이 효율적으로 구성되도록합니다 (불필요한 중간 문자열없이).


2

예, 루프가 완료되면 문자열로 변환하십시오.

String str = data.ToString().TrimEnd(',');

3
그것은 매우 비효율적입니다. 먼저 문자열로 변환 한 다음 트리밍합니다.
Piotr Stapp 2013 년

2
@Garath "비효율적"이라는 뜻이라면 동의하지 않을 것입니다. 그러나 그것은 효과적 일 입니다.
DonBoitnott 2013-06-20

2

두 가지 옵션이 있습니다. 첫 번째는 매우 사용하기 쉬운 Remove방법으로 매우 효과적입니다. 두 번째 방법은 ToString시작 색인 및 끝 색인과 함께 사용하는 것 입니다 ( MSDN 문서 ).



1

가장 간단한 방법은 Join () 메서드를 사용하는 것입니다.

public static void Trail()
{
    var list = new List<string> { "lala", "lulu", "lele" };
    var data = string.Join(",", list);
}

StringBuilder가 정말로 필요한 경우 루프 뒤의 끝 쉼표를 잘라냅니다.

data.ToString().TrimEnd(',');

4
data.ToString().TrimEnd(',');비효율적
bastos.sergio는

1
또한 ","로 끝나는 여러 줄이있을 수 있으므로 StringBuilder 개체를 String으로 변환하지 않을 수 있습니다.
Fandango68

0

잡았다 !!

이 스레드에 대한 대부분의 답변은 AppendLine아래와 같이 사용하면 작동하지 않습니다 .

var builder = new StringBuilder();
builder.AppendLine("One,");
builder.Length--; // Won't work
Console.Write(builder.ToString());

builder = new StringBuilder();
builder.AppendLine("One,");
builder.Length += -1; // Won't work
Console.Write(builder.ToString());

builder = new StringBuilder();
builder.AppendLine("One,");
Console.Write(builder.TrimEnd(',')); // Won't work

Fiddle Me

왜??? @ (& ** (& @ !!

문제는 간단하지만 알아내는 데 시간이 좀 걸렸습니다 . 끝에 2 개의 보이지 않는 문자가 더 CR있고 LF(캐리지 리턴 및 줄 바꿈) 이 있기 때문 입니다. 따라서 마지막 3 개의 문자를 제거해야합니다.

var builder = new StringBuilder();
builder.AppendLine("One,");
builder.Length -= 3; // This will work
Console.WriteLine(builder.ToString());

결론적으로

사용 Length--또는 Length -= 1당신이 마지막으로 호출 방법이 있다면 Append. Length =- 3마지막으로 호출 한 메서드 인 경우 사용 합니다 AppendLine.

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