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

나는 다음이있다

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

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

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



답변

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

data.Length--;

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

data.Length = 0;

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


답변

그냥 사용

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. 여기 에서 컴파일 가능한 예제를 찾을 수 있습니다.


답변

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

.TrimEnd(',')

또는 단순히 변경

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


답변

이건 어때..

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


답변

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

data.Length = data.Length - 1;


답변

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

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


답변

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