我有以下内容
data.AppendFormat("{0},",dataToAppend);
问题在于我正在循环中使用它,会有一个尾随逗号。有什么最好的方法可以删除尾随逗号吗?
我是否需要将数据更改为字符串,然后对其进行子字符串操作?
我有以下内容
data.AppendFormat("{0},",dataToAppend);
问题在于我正在循环中使用它,会有一个尾随逗号。有什么最好的方法可以删除尾随逗号吗?
我是否需要将数据更改为字符串,然后对其进行子字符串操作?
最简单且最有效率的方法是执行此命令:
data.Length--;
通过这样做,您将指针(即最后一个索引)向后移动一个字符,但不会更改对象的可变性。事实上,清除 StringBuilder
最好也使用 Length
(但是为了清晰起见,请确实使用 Clear()
方法,因为它的实现看起来像这样):
data.Length = 0;
再次说明,因为它不会改变分配表。可以将其视为说,“我不想再识别这些字节了”。现在,即使调用ToString()
,它也不会识别其长度后面的任何内容,实际上它也做不到。它是一个可变对象,为其分配比提供给它的空间更多的空间,它就是这样建造的。
data.Length = 0;
:这正是StringBuilder.Clear
所做的事情,因此为了表达意图更清晰,最好使用StringBuilder.Clear
。 - Eren ErsönmezClear()
的作用,但有趣的是,那是Clear()
方法的第一行。但是,你知道接口实际上会发出return this;
吗?现在这就是让我困扰的事情。将Length = 0
设置为更改您已经拥有的引用,为什么要返回自己呢? - Mike PerrenoudAppend
方法也会返回其自身。 - Eren Ersönmez只需使用
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)
string.Join(",", input)
- Tvde1我更喜欢操纵 StringBuilder 的长度:
data.Length = data.Length - 1;
data.Length--
或 --data.Length
? - iCollect.it Ltd--
或 ++
。不过你可以使用 data.Length -= 1
,或者这个答案也可以。 - Jason S如果您使用以下代码中的 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
为什么??? @(&**(&@!!
问题很简单,但我花了一些时间才弄清楚:因为在结尾处还有两个不可见字符CR
和LF
(回车符和换行符)。因此,您需要去掉最后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
。
public static void Trail()
{
var list = new List<string> { "lala", "lulu", "lele" };
var data = string.Join(",", list);
}
data.ToString().TrimEnd(',');
data.ToString().TrimEnd(',');
不够高效。 - bastos.sergiostring.Join
方法将一组项目转换为逗号分隔的字符串。它将确保没有前导或尾随逗号,并确保字符串的构建高效(不会产生不必要的中间字符串)。是的,等循环结束后将其转换为字符串:
String str = data.ToString().TrimEnd(',');
string.Join(",", yourCollection)
的意思是将yourCollection
集合中的元素用逗号连接成一个字符串。 - Vlad