如何使用C#处理CSV文件中的换行符?

我有一个Excel电子表格在C#中转换为CSV文件,但在处理换行符时遇到问题。 例如:

"John","23","555-5555" "Peter","24","555-5 555" "Mary,"21","555-5555" 

当我读取CSV文件时,如果记录没有以双引号(“)开头,那么就会出现换行错误,我必须将其删除。我有一些来自互联网的CSV读取器类但我担心它们在换行时会失败。

我该如何处理这些换行符?


非常感谢大家的帮助。

heres是我到目前为止所做的,我的记录有固定的格式,一切都从一开始

 JTW;...;....;...; JTW;...;...;.... JTW;....;...;.. ..;...;... (wrong record, line brak inserted) JTW;...;... 

所以我检查了; 在每行的[3]位置。 如果我写的是真的,如果假病附加在最后*删除换行符)

我现在遇到问题,因为我将文件保存为txt。

顺便说一句,我通过在excell中保存为csv将excell spreadshit转换为csv。 但我不确定客户是否这样做。

所以作为TXT的文件是完美的。 香港专业教育学院检查了记录和总数。 但现在我必须将它转换回csv,我真的很想在程序中做到这一点。 有人知道吗?

这是我的代码:

 namespace EditorCSV { class Program { static void Main(string[] args) { ReadFromFile("c:\\source.csv"); } static void ReadFromFile(string filename) { StreamReader SR; StreamWriter SW; SW = File.CreateText("c:\\target.csv"); string S; char C='a'; int i=0; SR=File.OpenText(filename); S=SR.ReadLine(); SW.Write(S); S = SR.ReadLine(); while(S!=null) { try { C = S[3]; } catch (IndexOutOfRangeException exception){ bool t = false; while (t == false) { t = true; S = SR.ReadLine(); try { C = S[3]; } catch (IndexOutOfRangeException ex) { S = SR.ReadLine(); t = false; } } } if( C.Equals(';')) { SW.Write("\r\n" + S); i = i + 1; } else { SW.Write(S); } S=SR.ReadLine(); } SR.Close(); SW.Close(); Console.WriteLine("Records Processed: " + i.ToString() + " ."); Console.WriteLine("File Created SucacessFully"); Console.ReadKey(); } } } 

CSV具有预定义的处理方式。 该站点提供了一个易于阅读的解释,说明了处理CSV的所有警告的标准方法 。

然而,没有理由不使用可靠的开源库来读取和写入CSV文件,以避免出现非标准错误。 LINQtoCSV是我最喜欢的库。 它以简洁的方式支持阅读和书写。

或者, CSV库上的这个SO问题将为您提供最受欢迎的选项列表。

而不是检查当前行是否缺少(“)作为第一个字符,而是检查最后一个字符是否为(”)。 如果不是,您知道您有换行符,您可以阅读下一行并将它们合并在一起。

我假设您的示例数据是准确的 – 字段用引号括起来。 如果引号可能不会分隔文本字段(或者在非文本数据中以某种方式找到新行),则所有投注都会关闭!

有一种在.NET中读取CSV文件的内置方法(需要添加Microsoft.VisualBasic程序集引用):

 public static IEnumerable ReadSV(TextReader reader, params string[] separators) { var parser = new Microsoft.VisualBasic.FileIO.TextFieldParser(reader); parser.SetDelimiters(separators); while (!parser.EndOfData) yield return parser.ReadFields(); } 

如果你正在处理非常大的文件,这个CSV阅读器声称是你能找到的最快的文件: http : //www.codeproject.com/Articles/9258/A-Fast-CSV-Reader

我最近使用这段代码来解析CSV文件中的行(这是一个简化版本):

 private void Parse(TextReader reader) { var row = new List(); var isStringBlock = false; var sb = new StringBuilder(); long charIndex = 0; int currentLineCount = 0; while (reader.Peek() != -1) { charIndex++; char c = (char)reader.Read(); if (c == '"') isStringBlock = !isStringBlock; if (c == separator && !isStringBlock) //end of word { row.Add(sb.ToString().Trim()); //add word sb.Length = 0; } else if (c == '\n' && !isStringBlock) //end of line { row.Add(sb.ToString().Trim()); //add last word in line sb.Length = 0; //DO SOMETHING WITH row HERE! currentLineCount++; row = new List(); } else { if (c != '"' && c != '\r') sb.Append(c == '\n' ? ' ' : c); } } row.Add(sb.ToString().Trim()); //add last word //DO SOMETHING WITH LAST row HERE! } 

也许你可以在ReadLine()期间计算(“)。如果它们是奇数,那将提升标志。你可以忽略这些行,或者获得接下来的两行并消除合并行的第一次”\ n“出现。

由于这个问题,我通常做的是逐行逐字逐字地阅读文本。

当你正在阅读每个角色时,你应该能够找出每个单元格的开始和停止位置,以及行和单元格中的换行符之间的区别:如果我没记错的话,对于Excel生成的文件无论如何,行开始使用\ r \ n,单元格中的换行符仅为\ r \ n。

听从专家的意见, 不要推出自己的CSV解析器 。

你的第一个想法是,“我如何处理新的换行符?”

你的下一个想法是,“我需要在引号内处理逗号。”

你的下一个想法是,“哦,废话,我需要处理引号内的引号。转义引号。双引号。单引号……”

这是一条通向疯狂的道路。 不要自己写。 找到一个具有广泛的unit testing覆盖率的图书馆,该图书馆覆盖了所有的硬件,并为您经历了地狱。 对于.NET,请使用免费的FileHelpers库 。

试试CsvHelper (我维护的库)。 它忽略了空行。 我相信你可以在FastCsvReader中设置一个标志来让它处理空行。

有一个示例解析器是c#,似乎正确处理您的情况。 然后,您可以读取您的数据并在读取后清除它的换行符。 第2部分是解析器, 第1部分介绍了编写器部分。

阅读该行。
分成列(字段)。
如果每行都有足够的列,则进行处理。
如果没有,请阅读下一行,并捕获剩余的列,直到获得所需的内容。
重复。

可以在每一行上使用一个简单的正则表达式。 匹配时,您将处理匹配中的每个字段。 如果找不到匹配项,则跳过该行。

正则表达式看起来像这样。

 Match match = Regex.Match(line, @"^(?:,?(?['"](?.*?\k'q')|(?[^,]*))+$"); if (match.Success) { foreach (var capture in match.Groups["field"].Captures) { string fieldValue = capture.Value; // Use the value. } } 

看一下FileHelpers Library它支持使用换行符读取\写入CSV以及读取\写入excel

LINQy解决方案:

 string csvText = File.ReadAllText("C:\\Test.txt"); var query = csvText .Replace(Environment.NewLine, string.Empty) .Replace("\"\"", "\",\"").Split(',') .Select((i, n) => new { i, n }).GroupBy(a => an / 3);