【问题标题】:How to filter CSV data using C#如何使用 C# 过滤 CSV 数据
【发布时间】:2019-07-31 09:02:36
【问题描述】:

我有一个包含字符串数据的 csv 文件,如果“作业”列为空,我想过滤掉所有数据行,创建一个新的 csv 文件并将剩余的数据行写入其中。

字符串数据中包含双引号“”,第一行的“Id”、“Name”、“Job”实际上是字符串数据,而不是列,也就是说如果数据行的第三个字符串数据是double引用 "" ,它被过滤掉了。

"Id" , "Name"    , "Job"
"1"  , "Alan"    , "Engineer"
"2"  , "Bob"     , "Technician"
"3"  , "Charlie" , ""
"4"  , "Danny"   , ""

根据上面的csv预计剩下的数据是

"Id" , "Name"    , "Job"
"1"  , "Alan"    , "Engineer"
"2"  , "Bob"     , "Technician"

【问题讨论】:

  • 到目前为止你有什么尝试?
  • 我在做什么?我将 csv 转换为 excel,然后使用 excel 上传表单并在 c# 中获取值并处理它们,然后将它们放入另一个 excel 或 csv 文件中。对于 Excel 上传参考,请检查此链接 => aspsnippets.com/Articles/…
  • 您是在格式化这些示例以向我们展示非常对齐的“列”还是“列”之间真的有所有这些空格?
  • @Thameem,Excel 读取 CSV?这是一个非常沉重的工具。像 CSVHelper 这样的东西更适合。
  • @Steve,说到正确的工具,csvReader.Configuration.TrimOptions 没什么大不了的。

标签: c# string csv


【解决方案1】:

您可以使用以下方法来做到这一点:

string[] lines = File.ReadAllLines("csvFile.csv");
List<string[]> csvData = new List<string[]>();
foreach(string line in lines)
{
    using (TextFieldParser parser = new TextFieldParser(new StringReader(line)))
    {
        parser.TextFieldType = FieldType.Delimited;
        parser.SetDelimiters(",");
        parser.HasFieldsEnclosedInQuotes = true;
        parser.TrimWhiteSpace = true;
        while (!parser.EndOfData)
            csvData.Add(parser.ReadFields());
    }
}

//Select all lines in csv file in which third column are not empty
List<string[]> filteredCsvData = csvData.Where(x => !string.IsNullOrWhiteSpace(x[2])).ToList();

StringBuilder builder = new StringBuilder();
foreach (string[] line in filteredCsvData)
{
    //Quote all columns back
    string[] quotedLine = Array.ConvertAll(line, x => '"' + x + '"');
    builder.AppendLine(string.Join(',', quotedLine));
}
File.WriteAllText ("newCsvFile.csv", builder.ToString());

如果您只需要引用那些使用逗号的列:string[] quotedLine = Array.ConvertAll(line, x =&gt; '"' + x + '"');

注意 以下代码使用 Microsoft.VisualBasic.FileIO.TextFieldParser 作为 CSV 解析器,以便在 .Net Framework 中使用它,您需要将 Microsoft.VisualBasic 包含到您的项目中(在 .Net Core 3.0 中也可用)

【讨论】:

  • 谢谢,你的回答通俗易懂,给了我一些启发,但是我在添加VB.FileIO引用时遇到了一些问题,现在问题已经解决了
【解决方案2】:

Step1:读取 CSV 文件并创建一个 List 对象。

使用 Poco 类:

public class Foo
{
    public string Id { get; set; }
    public string Name { get; set; }        
    public string Job { get; set; }
}

您可以使用CSV helper进行读取,配置如下:

Configuration.Delimiter=",";
Configuration.HasHeaderRecord=false; // has your first line look like header but is not
Configuration.TrimOptions= TrimOptions.Trim | TrimOptions.InsideQuotes;
Configuration.RegisterClassMap<FooMap>();

Step2:过滤结果

records.Where(x=> !string.IsNullOrEmpty(x.Job))

完整的代码示例,以及live demo:

        var input = @"""Id"" , ""Name""    , ""Job""
""1""  , ""Alan""    , ""Engineer""
""2""  , ""Bob""     , ""Technician""
""3""  , ""Charlie"" , """"
""4""  , ""Danny""   , """"";

        var records= new List<Foo>();

        //reading CSV to List Foo;
        using (TextReader reader = new StringReader(input))
        using (var csvReader = new CsvReader(reader))
        {
            csvReader.Configuration.Delimiter=",";
            csvReader.Configuration.HasHeaderRecord=false; 
            csvReader.Configuration.TrimOptions=TrimOptions.Trim | TrimOptions.InsideQuotes;
            csvReader.Configuration.RegisterClassMap<FooMap>();
            records = csvReader.GetRecords<Foo>().ToList();
        }

        records.Dump();

        //Filter
        var result = records.Where(x=> !string.IsNullOrEmpty(x.Job)).ToList();
        result.Dump();
    }

    public class Foo
    {
        public string Id { get; set; }
        public string Name { get; set; }        
        public string Job { get; set; }
    }
    public class FooMap : ClassMap<Foo>
    {
        public FooMap()
        {
            Map(m => m.Id).Index(0);
            Map(m => m.Name).Index(1);          
            Map(m => m.Job).Index(2);

            //mapping with column header
            /*Map(m => m.Id).Name("Id");
            Map(m => m.Name).Name("Name");          
            Map(m => m.Job).Name("Job");*/
        }
    }

【讨论】:

    【解决方案3】:

    如果你有csv辅助工具,你可以使用工具解析文件到List或DataTable,过滤数据并导出。

    如果没有,可以试试:

    using (var reader = new StreamReader(sourcePath))
                {
                    using (var writer = new StreamWriter(destiPath))
                    {
                        String line;
                        while ((line = reader.ReadLine()) != null)
                        {
                            var list = line.Split(',');
                            if (list.Length > 2 && !string.IsNullOrEmpty(list[2].Trim(' ','\"')))
                            {
                                writer.WriteLine(line);
                            }
                        }
                    }
                }
    

    【讨论】:

    • 谢谢,这个比较容易理解,给了我一些关于字符串操作的启发
    • 它不是标准解析的 csv 辅助工具
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多