使用 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#中如何使用split方法

带有嵌入式清单的 C# 4.0 应用程序是不是需要在客户端计算机上安装数字证书或强名称?

.NET(C#) Json.Net(newtonsoft)使用LINQ查询JSON数据

我可以在面向 .Net 3.5 的项目中使用所有 C# 4.0 功能吗?

使用 .net 的 (C#) System.Net.Cookie 处理 cookie 值中的逗号