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


90

我有以下

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

问题是我在循环中使用它,并且会有一个试验逗号。删除尾部逗号的最佳方法是什么?

我是否必须将数据更改为字符串的子字符串呢?


10
string.Join(",", yourCollection)?编辑:添加为答案。
Vlad13年


@Chris:这样,您根本不需要StringBuilder。
Vlad13年

也许您可以避免添加逗号而不是事后将其删除。请参阅:stackoverflow.com/questions/581448/…(乔恩·斯凯特的回答)
Paolo Falabella 2013年

@Vlad是的,对不起,我误读了;我以为您提供的建议是更改最终构建的字符串,而不是完全替代他的循环。(我以为我及时删除了我的评论,不要猜吧!)
克里斯·辛克莱

Answers:


222

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

data.Length--;

通过这样做,您可以将指针(即最后一个索引)移回一个字符,但不会更改对象的可变性。实际上,清除a StringBuilder也是最好LengthClear()方法(但实际上是为了清楚起见使用该方法,因为这是其实现的样子):

data.Length = 0;

再次,因为它不会更改分配表。想起来就像说,我不想再识别这些字节了。现在,即使调用ToString(),它也无法识别超出其范围的任何内容Length。这是一个可变的对象,比您提供的对象分配更多的空间,它是通过这种方式简单构建的。


2
re data.Length = 0;:确实是StringBuilder.Clear这样,所以StringBuilder.Clear为了清楚起见最好使用。
ErenErsönmez2013年

@ErenErsönmez,足够公平的朋友,我应该更清楚地说明那是什么Clear(),但很有趣。那是该方法的第一行Clear()。但是,您是否知道接口实际上会发出一个return this;。现在,那件事使我丧命。设置Length = 0已经存在的参考的更改,为什么要返回自己?
Mike Perrenoud 2013年

12
我认为这是为了能够以“流利”的方式使用。Append也返回自己。
ErenErsönmez13年

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 2014年

1
@Seabizkit:当然可以!顺便说一句,整个问题都与C#有关。
弗拉德(Flad)

1
@弗拉德我明白了,只有双重检查,因为我正在做像原始测试这样的简单测试,而且它们没有产生相同的结果。string.Join(",", yourCollection)仍然有一个,结尾。因此上述ie string.Join(",", yourCollection)效率很低,并且不能单独删除它。
Seabizkit

2
@Seabizkit:很奇怪!你能举个例子吗?在我的代码中,它可以完美地工作: ideone.com/aj8PWR
Vlad

2
多年使用循环来构建字符串生成器,然后删除结尾的逗号,我本可以使用它。谢谢你的提示!
卡弗曼

11

循环后使用以下内容。

.TrimEnd(',')

或只是更改为

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

4
他正在使用StringBuilder而不是字符串。此外,它是非常无效的:首先转换为字符串,然后修剪。
Piotr Stapp 2013年

string.Join(",", input)
Tvde1

10

这个怎么样..

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

Trim返回字符串的新实例,它不会更改
stringbuilder

@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

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 2013年

1
另外,您可能不想将StringBuilder对象转换为String,因为它可能有多行以“,”结尾
Fandango68 '18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.