C#解析含引号数组字段的CSV:替代line.Split(',')的方案
解决C#中带引号嵌套逗号的CSV解析问题
这个场景太常见了!直接用string.Split(',')肯定会踩坑,因为引号包裹的内容里的逗号是字段内部的,不是分隔符。在C#里有几种高效的解决方案,我给你逐一说明:
方法1:使用.NET内置的TextFieldParser
虽然它在Microsoft.VisualBasic.FileIO命名空间下,但别担心,.NET Core/.NET 5+都能直接用,不需要额外安装库,适合轻量场景。
首先定义你的目标类:
public class MyCsvData { public string[] Letters { get; set; } public string Foo { get; set; } public string Goo { get; set; } }
然后编写解析代码:
using Microsoft.VisualBasic.FileIO; using System.Collections.Generic; using System.IO; public List<MyCsvData> ParseCsv(string filePath) { var result = new List<MyCsvData>(); using (var parser = new TextFieldParser(filePath)) { parser.TextFieldType = FieldType.Delimited; parser.SetDelimiters(","); parser.HasFieldsEnclosedInQuotes = true; // 关键:告诉解析器处理引号包裹的字段 while (!parser.EndOfData) { string[] fields = parser.ReadFields(); // 第一个字段是引号包裹的"a1,b1,c1,d1",直接分割成数组 string[] letters = fields[0].Split(','); // 后续字段直接取,注意去除可能的空格 var data = new MyCsvData { Letters = letters, Foo = fields[1].Trim(), Goo = fields[2].Trim() }; result.Add(data); } } return result; }
这个方法会自动忽略引号内的逗号,正确分割出三个顶级字段:"a1,b1,c1,d1"、foo1、goo1,然后你再把第一个字段分割成数组即可。
方法2:使用第三方库CsvHelper(推荐)
如果你的CSV格式更复杂(比如有转义引号、多行字段等),CsvHelper是行业标准,功能强大且灵活。
首先通过NuGet安装CsvHelper包,然后编写代码:
using CsvHelper; using CsvHelper.Configuration; using System.Collections.Generic; using System.Globalization; using System.IO; // 定义目标类 public class MyCsvData { public string[] Letters { get; set; } public string Foo { get; set; } public string Goo { get; set; } } // 定义字段映射规则 public class MyCsvDataMap : ClassMap<MyCsvData> { public MyCsvDataMap() { Map(m => m.Letters).Convert(args => args.Row.GetField<string>(0).Split(',')); Map(m => m.Foo).Index(1).Trim(); Map(m => m.Goo).Index(2).Trim(); } } public List<MyCsvData> ParseCsvWithCsvHelper(string filePath) { var config = new CsvConfiguration(CultureInfo.InvariantCulture) { Delimiter = ",", Quote = '"', TrimOptions = TrimOptions.Trim // 自动去除字段前后空格 }; using (var reader = new StreamReader(filePath)) using (var csv = new CsvReader(reader, config)) { csv.Context.RegisterClassMap<MyCsvDataMap>(); return csv.GetRecords<MyCsvData>().ToList(); } }
CsvHelper会自动处理所有CSV的边缘情况,而且代码更简洁易维护,非常适合生产环境使用。
方法3:手动解析(不推荐,除非特殊场景)
如果不想用任何库,你可以手动遍历字符,跟踪是否处于引号内,遇到逗号时只有在引号外才分割。但这种方式需要处理很多边界情况(比如转义的""、空字段等),示例代码大概是这样:
public List<MyCsvData> ParseCsvManually(string filePath) { var result = new List<MyCsvData>(); foreach (var line in File.ReadLines(filePath)) { var fields = new List<string>(); bool inQuotes = false; var currentField = new char[line.Length]; int idx = 0; foreach (char c in line) { if (c == '"') { inQuotes = !inQuotes; } else if (c == ',' && !inQuotes) { fields.Add(new string(currentField, 0, idx).Trim()); idx = 0; } else { currentField[idx++] = c; } } // 添加最后一个字段 fields.Add(new string(currentField, 0, idx).Trim()); if (fields.Count >=3) { result.Add(new MyCsvData { Letters = fields[0].Split(','), Foo = fields[1], Goo = fields[2] }); } } return result; }
这种方式容易遗漏场景,比如如果字段里有""(表示一个双引号),上面的代码就处理不了,所以除非万不得已,优先用前两种方法。
内容的提问来源于stack exchange,提问作者Yogi_Bear
相关产品推荐
相关产品推荐

