从使用stringbuilder构建的字符串中删除最后一个字符的最佳方法

本文关键字:删除 最后一个 字符 方法 最佳 字符串 stringbuilder 构建 | 更新日期: 2023-09-27 18:19:08

我有以下内容

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

这样做的问题是我在循环中使用它,并且后面会有一个逗号。去掉末尾逗号的最好方法是什么?

我是否必须将数据更改为字符串,然后将其子字符串?

从使用stringbuilder构建的字符串中删除最后一个字符的最佳方法

最简单和最有效的方法是执行以下命令:

data.Length--;

通过这样做,您将指针(即最后一个索引)向后移动一个字符,但您不改变对象的可变性。事实上,清除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。您可以在这里找到一个可编译的示例。

这个怎么样?

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

在循环后使用以下代码。

.TrimEnd(',')

或者直接改成

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

我更喜欢操作stringbuilder的长度:

data.Length = data.Length - 1;

找到了!

如果你像下面这样使用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

小提琴我

为什么? ? @ (和* *(和@ ! !

这个问题很简单,但花了我一段时间才弄清楚:因为在CRLF(回车和换行)的末尾有2个不可见的字符。因此,您需要去掉最后3个字符:

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

如果最后调用的方法是Append,则使用Length--Length -= 1。如果您上次调用的方法是AppendLine,则使用Length =- 3

我建议你改变你的循环算法:

  • 前加逗号,而不是项目后
  • 使用以false开头的布尔变量,不使用第一个逗号
  • 测试后将布尔变量设置为true

您应该使用string.Join方法将项目集合转换为逗号分隔的字符串。它将确保没有前后逗号,并确保字符串被有效地构造(没有不必要的中间字符串)。

最简单的方法是使用Join()方法:

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

如果您确实需要StringBuilder,请在循环后删除结束逗号:

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

是的,在循环完成后将其转换为字符串:

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

您有两个选择。第一个是非常容易使用的Remove方法,它是相当有效的。第二种方法是使用ToString与开始索引和结束索引(MSDN文档)

这里也有类似的问题

我喜欢使用StringBuilder扩展方法。

RemoveLast方法

将stringbuilder的长度缩短1;

 StringBuilder sb = new StringBuilder();
 sb.Length--;

我知道这不是有效的方式,因为它转换成sb = sb-1;

备选有效方案

sb.Remove(starting_index, how_many_character_to_delete);

在我们的例子中是

sb.Remove(sb.length-1,1)