CSV字符串处理
创建CSV字符串(伪代码)的典型方法:
- 创建一个CSV容器对象(如C#中的StringBuilder)。
- 遍历我们要添加的字符串,在每个字符串之后添加一个逗号。
- 循环后,删除最后一个多余的逗号。
代码示例:
public string ReturnAsCSV(ContactList contactList) { StringBuilder sb = new StringBuilder(); foreach (Contact c in contactList) { sb.Append(c.Name + ","); } sb.Remove(sb.Length - 1, 1); //sb.Replace(",", "", sb.Length - 1, 1) return sb.ToString(); }
我喜欢通过检查容器是否为空来添加逗号的想法,但这不意味着要进行更多的处理,因为它需要在每次出现时检查字符串的长度吗?
我觉得应该有一种更容易/更清洁/更有效的方法来删除最后一个逗号。有任何想法吗?
解决方案
回答
相反,我们可以将逗号添加为foreach中的第一件事。
如果((sb.Length> 0)sb.Append(",");`
回答
如何跟踪我们是否在第一个项目上,并且如果不是第一个项目,仅在该项目之前添加逗号。
public string ReturnAsCSV(ContactList contactList) { StringBuilder sb = new StringBuilder(); bool isFirst = true; foreach (Contact c in contactList) { if (!isFirst) { // Only add comma before item if it is not the first item sb.Append(","); } else { isFirst = false; } sb.Append(c.Name); } return sb.ToString(); }
回答
我们可以对对象使用LINQ:
string [] strings = contactList.Select(c => c.Name).ToArray(); string csv = string.Join(",", strings);
显然,所有这些都可以在一行中完成,但是在两行中则要清晰一些。
回答
抱歉,特定于PHP的示例,但可能会对某些人有所帮助。
回答
I like the idea of adding the comma by checking if the container is empty, but doesn't that mean more processing as it needs to check the length of the string on each occurrence?
我们过早地进行了优化,对性能的影响可以忽略不计。
回答
我们还可以创建一个c.Name数据数组,并使用String.Join方法创建行。
public string ReturnAsCSV(ContactList contactList) { List<String> tmpList = new List<string>(); foreach (Contact c in contactList) { tmpList.Add(c.Name); } return String.Join(",", tmpList.ToArray()); }
这可能不如StringBuilder方法的性能好,但肯定看起来更干净。
另外,我们可能要考虑使用.CurrentCulture.TextInfo.ListSeparator而不是硬编码的逗号-如果要将输出导入到其他应用程序中,则可能会有问题。 ListSeparator可能在不同的文化中有所不同,并且至少MS Excel支持此设置。所以:
return String.Join( System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator, tmpList.ToArray());
回答
修剪一下怎么样?
public string ReturnAsCSV(ContactList contactList) { StringBuilder sb = new StringBuilder(); foreach (Contact c in contactList) { sb.Append(c.Name + ","); } return sb.ToString().Trim(','); }
回答
只是想一想,但请记住在字段值中使用逗号和引号("),否则CSV文件可能会破坏使用者的阅读器。
回答
不要忘记我们的老朋友"为"。它看起来不像foreach那样好看,但是它具有能够从第二个元素开始的优点。
public string ReturnAsCSV(ContactList contactList) { if (contactList == null || contactList.Count == 0) return string.Empty; StringBuilder sb = new StringBuilder(contactList[0].Name); for (int i = 1; i < contactList.Count; i++) { sb.Append(","); sb.Append(contactList[i].Name); } return sb.ToString(); }
我们还可以将第二个Append包裹在" if"中,以测试Name属性是否包含双引号或者逗号,如果是,则对其进行适当的转义。
回答
代码不完全符合完整的CSV格式。如果我们只是从没有逗号,前导/尾随空格,制表符,换行符或者引号的数据生成CSV,那应该没问题。但是,在大多数实际数据交换方案中,我们确实需要完整的实现。
为了生成适当的CSV,我们可以使用以下命令:
public static String EncodeCsvLine(params String[] fields) { StringBuilder line = new StringBuilder(); for (int i = 0; i < fields.Length; i++) { if (i > 0) { line.Append(DelimiterChar); } String csvField = EncodeCsvField(fields[i]); line.Append(csvField); } return line.ToString(); } static String EncodeCsvField(String field) { StringBuilder sb = new StringBuilder(); sb.Append(field); // Some fields with special characters must be embedded in double quotes bool embedInQuotes = false; // Embed in quotes to preserve leading/tralining whitespace if (sb.Length > 0 && (sb[0] == ' ' || sb[0] == '\t' || sb[sb.Length-1] == ' ' || sb[sb.Length-1] == '\t' )) { embedInQuotes = true; } for (int i = 0; i < sb.Length; i++) { // Embed in quotes to preserve: commas, line-breaks etc. if (sb[i] == DelimiterChar || sb[i]=='\r' || sb[i]=='\n' || sb[i] == '"') { embedInQuotes = true; break; } } // If the field itself has quotes, they must each be represented // by a pair of consecutive quotes. sb.Replace("\"", "\"\""); String rv = sb.ToString(); if (embedInQuotes) { rv = "\"" + rv + "\""; } return rv; }
可能不是世界上最高效的代码,但是它已经过测试。与快速示例代码相比,现实世界糟透了:)
回答
我以前用过这种方法。 StringBuilder的Length属性不是只读的,因此通过一种方式减去它会截断最后一个字符。但是我们必须确保长度不以零开头(如果列表为空,这会发生),因为将长度设置为小于零是错误的。
public string ReturnAsCSV(ContactList contactList) { StringBuilder sb = new StringBuilder(); foreach (Contact c in contactList) { sb.Append(c.Name + ","); } if (sb.Length > 0) sb.Length -= 1; return sb.ToString(); }
回答
为什么不在那里使用开源CSV库之一?
我知道听起来很简单,但看起来却很简单,但是正如注释和代码段所表明的那样,它不仅仅令人眼前一亮。除了处理完全的CSV合规性之外,我们最终还需要处理读取和写入CSV ...,并且可能需要文件处理。
我以前在一个项目中使用过Open CSV(但是还有很多其他项目可供选择)。这无疑使我的生活更加轻松。 ;)