如何使用 LINQ 读取 csv,某些列包含 ,



我有一个CSV,方式如下。"India,Inc"是一个公司名称,它是单个值,其中包含 ,其中

如何在 LINQ 中获取值

12321,32432,423423,凯文·奥布莱恩,"印度公司",234235,23523452,235235

假设您将始终拥有指定的列,并且唯一的变量是公司名称可以包含逗号,则此UGLY代码可以帮助您实现目标。

        var file = File.ReadLines("test.csv");
        var value = from p in file
                     select new string[]
                    { p.Split(',')[0],
                      p.Split(',')[1],
                      p.Split(',')[2],
                      p.Split(',')[3],
                      p.Split(',').Count() == 7 ? p.Split(',')[4] :
                        (p.Split(',').Count() > 7 ? String.Join(",",p.Split(',').Skip(4).Take(p.Split(',').Count() - 7).ToArray() ) : ""),
                      p.Split(',')[p.Split(',').Count() - 3],
                      p.Split(',')[p.Split(',').Count() - 2],
                      p.Split(',')[p.Split(',').Count() - 1]
                     };

正则表达式可以工作,由于递归性质,有点讨厌,但它确实实现了您的目标。

        List<string> matches = new List<string>();
        string subjectString = "12321,32432,423423,Kevin O'Brien,"India,Inc",234235,23523452,235235";
        Regex regexObj = new Regex(@"(?<="")b[123456789a-z,']+b(?="")|[123456789a-z']+", RegexOptions.IgnoreCase);
        Match matchResults = regexObj.Match(subjectString);
        while (matchResults.Success)
        {
            matches.Add(matchResults.Value);
            // matched text: matchResults.Value
            // match start: matchResults.Index
            // match length: matchResults.Length
            matchResults = matchResults.NextMatch();
        }

在大多数情况下,这应该就足够了。 它处理带引号的字符串、其中带有双引号的字符串以及嵌入的逗号。

var subjectString = "12321,32432,423423,Kevin O'Brien,"India,Inc",234235,"Test End""","""Test Start","Test""Middle",23523452,235235";
var result=Regex.Split(subjectString,@",(?=(?:[^""]*""[^""]*"")*[^""]*$)")
  .Select(x=>x.StartsWith(""") && x.EndsWith(""")?x.Substring(1,x.Length-2):x)
  .Select(x=>x.Replace("""","""));

但是,如果您有一个包含单双引号的字段,并且字符串本身没有用双引号括起来,那么它确实会中断 - 这在CSV文件的大多数定义中是无效的,其中任何包含CR,LF,逗号或双引号的字段都必须括在双引号中。

对于小型 CSV 文件,您应该能够重复使用相同的正则表达式来换行。 较大的你会想要一个更好的实现。 将双引号替换为 LF,并删除匹配的引号(不带引号的 LF)。 然后再次使用正则表达式将引号替换为 CR,并在匹配时拆分。

另一种选择是使用CSVHelper而不是托盘来重新发明轮子

        var csv = new CsvHelper.CsvReader(new StreamReader("test.csv"));
        while (csv.Read())
        {
            Console.WriteLine(csv.GetField<int>(0));
            Console.WriteLine(csv.GetField<string>(1));
            Console.WriteLine(csv.GetField<string>(2));
            Console.WriteLine(csv.GetField<string>(3));
            Console.WriteLine(csv.GetField<string>(4));
        }

指导

我推荐 LINQ 到 CSV,因为它足够强大,可以处理特殊字符,包括逗号、引号和小数。他们真的为你解决了很多这些问题。

只需几分钟即可完成设置,而且非常值得花时间,因为您不会像使用自定义代码那样遇到这些类型的问题。以下是基本步骤,但一定要按照上面链接中的说明进行操作。

  1. 安装 Nuget 包
  2. 创建一个类来表示行项目(以字段在 csv 中的命名方式命名字段)
  3. 使用 CsvContext.Read() 读取 IEnumerable,您可以使用 LINQ 轻松操作
  4. 使用 CsvContext.Write() 将列表或 IEnumerable 写入 CSV

这非常容易设置,代码很少,并且比自己动手更具可扩展性。

因为您只读取逗号分隔的值,所以如果您只是将它们视为任何其他字符,则空格应该不会引起问题。

var values = File.ReadLines(path)
    SelectMany(line => line.Split(','));

最新更新