Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用C#.Net 4.0 LINQ嵌入逗号的CSV_Linq_C# 4.0_.net 4.0_Csv - Fatal编程技术网

使用C#.Net 4.0 LINQ嵌入逗号的CSV

使用C#.Net 4.0 LINQ嵌入逗号的CSV,linq,c#-4.0,.net-4.0,csv,Linq,C# 4.0,.net 4.0,Csv,我试图找到一种优雅的方式通过4.0 linq读取cvs字符串,但由于引号之间嵌入了逗号,所以有点失败。以下是3列3行的示例: 日期、年份、备忘录文本 “2011-01-01”、“0.5”、“备忘录文本 备忘录文本继续 继续,然后是逗号,但备忘录中有引号“ “2010-01-01”、“0.5”、“备忘录文本、不带换行符的备忘录” “2009-01-01”、“1.0”、“纯备忘录文本” 到目前为止,我已经提出了以下错误代码,作为将其他堆栈交换位合并在一起的方法。这不起作用,因为回车符换行符将备注文本

我试图找到一种优雅的方式通过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来实现这一点

事实上,对于.Net的答案是建议不要自己做这件事——有大量的第三方库可以让这件事变得简单:


如果您可以更改文件的结构,我建议您找到一个在内容中其他地方不使用的唯一分隔符(即“;”)

然后,使用第三方库(如此库)显然可以简化任务

您可以使用这样一种干净的语法:

var memos = from p in myFile
            select new { p.Date, p.DecimalYears, p.MemoText };

以下是我使用的代码,以防这对将来的某个人或其他人感到有必要对其进行微调

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
                }
            }
        }
    }
}

以下是Eric White提出的一个很好的扩展方法,可以满足您的CSV需求:

  • 只有逗号对分隔符有效
  • 可以引用值。引号被删掉了
  • 引用的值可以有内部逗号
  • 引用的值也可以有内部转义序列:反斜杠 后跟任何字符,包括引号(\”)、反斜杠(\)或 任何其他字符(\a)
  • CsvSplit将为格式不正确的字符串引发异常

我想我已经下定决心要在LINQ.net 4.0中实现这一点,在上面的代码片段中,我是否可能只差一行或多行?当然,可能还有更多的条件我还没有遇到,这正是我现在所知道的。文件解析是一个打破许多项目的主题。一切都很好,直到有人在某个字段中输入了错误的值,或者你雇用了奥康纳先生等等。我只想从那些在我之前经历过所有痛苦的人身上吸取教训:-)我最终使用了您附加的stackoverflow链接中的TextFieldParser。非常好,谢谢!哇,耶,如果我能控制csv的渲染,那就太好了。不幸的是,它来自salesforce bulkapi。我可以重新格式化输出,但可能会增加额外的开销。至少您不是唯一一个遇到此问题的人: