使用 C# .Net 4.0 LINQ 嵌入逗号的 CSV
Posted
技术标签:
【中文标题】使用 C# .Net 4.0 LINQ 嵌入逗号的 CSV【英文标题】:CSV with embedded commas using C# .Net 4.0 LINQ 【发布时间】:2012-01-11 11:26:26 【问题描述】:我正在尝试找到一种通过 4.0 linq 读取 cvs 字符串的优雅方法,但由于引号之间嵌入了逗号而有些不成功。下面是一个 3 列 3 行的例子:
日期、年份、备忘录文本 "2011-01-01","0.5","备忘录文本 备忘录文本继续 还在继续,然后是逗号,但备忘录是用引号引起来的" "2010-01-01","0.5","备忘录文本,没有换行符的备忘录" "2009-01-01","1.0","纯备忘录文本"
到目前为止,我已经提出了以下错误代码作为将其他堆栈交换位组合在一起。这不起作用,因为备忘录文本中的回车换行符将备忘录文本分成多个字段。
using (var reader = new StreamReader(getReader))
var records = reader.ReadToEnd().Split(new string[] "\r\n" , StringSplitOptions.RemoveEmptyEntries);
var enumRecords = records.Skip(1).Take(1);
using (var dc = new DataContext())
foreach (var record in enumRecords
.Select(x => x.Trim()
.Split(new char[] ',' ))
.Select(fields => new Entity
Date = (!string.IsNullOrEmpty(record.ElementAt(0))) ? Convert.ToDateTime(record.ElementAt(0)) : default(DateTime),
DecimalYears = record.ElementAt(1),
MemoText = record.ElementAt(2)
))
//Commit DataContext
单独使用逗号分割时没有骰子,因为引用的文本之间存在逗号:
using (var reader = new StreamReader(getReader))
var sdata = reader.ReadToEnd();
using (var dc = new DataContext())
var query = sdata
.Split(new string[] "," , StringSplitOptions.RemoveEmptyEntries)
.Replace(Environment.NewLine, string.Empty)
.Replace("\"\"", "\",\"")
.Select((i, n) => new i, n )
.GroupBy(a => a.n / 3)
.Skip(1).Take(1);
foreach (var fields in query)
var newEntity = new Entity();
newEntity.Date = (!string.IsNullOrEmpty(fields.ElementAt(0).i)) ? Convert.ToDateTime(fields.ElementAt(0).i) : default(DateTime);
newEntity.DecimalYears = fields.ElementAt(1).i;
newEntity.MemoText = fields.ElementAt(2).i;
到目前为止,似乎一个简单的目标是接近冗长丑陋的代码,可能有人有一个干净而实用的方法来使用 LINQ 来解决这个问题?
【问题讨论】:
【参考方案1】:.Net 的实际答案建议不要自己动手 - 有大量第三方库可以让这变得简单:
CSV File Imports in .Net
【讨论】:
我想我已经有点决心在 LINQ .net 4.0 中完成这项工作,我是否可能在上述代码 sn-ps 中仅差一行或多行? 当然,可能还有很多我没有遇到过的情况,这只是我目前所知道的。 文件解析是一个在很多项目中都被打破的话题。一切都很好,除非有人在某个字段中输入了错误的值,或者您雇用了 O'Connor 先生等等。我只是利用那些在我之前经历过所有痛苦的人的教训:-) 我最终使用了您附加的 *** 链接中的 TextFieldParser。效果很好,非常感谢!【参考方案2】:这是 Eric White 的一个很好的扩展方法,可以处理您的 CSV 要求:
只有逗号对分隔符有效 可以引用值。引号被修剪 引用的值可以有内部逗号 引用的值也可以有内部转义序列:反斜杠 后跟任何字符,包括引号 (\")、反斜杠 (\) 或 任何其他字符 (\a) CsvSplit 会对格式不正确的字符串抛出异常http://blogs.msdn.com/b/ericwhite/archive/2008/09/30/linq-to-text-and-linq-to-csv.aspx
【讨论】:
【参考方案3】:如果您可以更改文件的结构,我建议您找到一个不会在您的内容的其他地方使用的唯一分隔符(即“;”)。
然后,使用第三方库(如LINQ to CSV)显然会减轻任务。
您可以使用这样的简洁语法:
var memos = from p in myFile
select new p.Date, p.DecimalYears, p.MemoText ;
【讨论】:
哇,是的,如果我能够控制渲染 csv,那就太好了。不幸的是,它来自salesforce bulkapi。我可以重新格式化输出,但可能会产生额外的开销。 至少你不是唯一一个遭受这个问题的人:success.salesforce.com/ideaview?id=08730000000BpAeAAK【参考方案4】:这是我使用的代码,以防将来对某人有帮助,或者其他人有微调它的冲动。
using (var reader = new StreamReader(Service.GetResult(batchInfo, results.result[0])))
using (var dc = new DataContext())
using (var parser = new TextFieldParser(reader))
parser.Delimiters = new string[] "," ;
parser.TrimWhiteSpace = true;
while (true)
string[] parts = parser.ReadFields();
if (parts == null) break;
try
var newEntity = new Entity();
newEntity.ID = Guid.NewGuid();
newEntity.Date = (!string.IsNullOrEmpty(parts[0])) ? Convert.ToDateTime(parts[0]) : default(DateTime);
newEntity.Year = parts[1];
newEntity.MemoText = parts[2];
dc.Entity.InsertOnSubmit(newEntity);
dc.SubmitChanges();
catch (MalformedLineException mle)
string message = mle.Message;
//TODO: log an error
【讨论】:
以上是关于使用 C# .Net 4.0 LINQ 嵌入逗号的 CSV的主要内容,如果未能解决你的问题,请参考以下文章
如何在 linq 查询 c# 中的 WHERE 语句后嵌入动态 OR 条件
带有嵌入式清单的 C# 4.0 应用程序是不是需要在客户端计算机上安装数字证书或强名称?
.NET(C#) Json.Net(newtonsoft)使用LINQ查询JSON数据