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

时间:2009-07-24 17:52:18

标签: c# csv

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

"John","23","555-5555"

"Peter","24","555-5
555"

"Mary,"21","555-5555"

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

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


非常感谢大家的帮助。

继承人是我到目前为止所做的,我的记录有固定的格式,所有都以

开头
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();


        }




        }
    } 

15 个答案:

答案 0 :(得分:14)

CSV已预定义处理该方法。该网站提供了标准way to handle all the caveats of CSV的简单易懂的解释。

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

或者,this SO question on CSV libraries会为您提供最受欢迎的选项列表。

答案 1 :(得分:5)

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

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

答案 2 :(得分:3)

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

public static IEnumerable<string[]> 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

答案 3 :(得分:2)

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

private void Parse(TextReader reader)
    {
        var row = new List<string>();
        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<string>();
            }
            else
            {
                if (c != '"' && c != '\r') sb.Append(c == '\n' ? ' ' : c);
            }
        }

        row.Add(sb.ToString().Trim()); //add last word

        //DO SOMETHING WITH LAST row HERE!
    }

答案 4 :(得分:1)

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

答案 5 :(得分:1)

由于这个问题,我通常会逐行逐字逐句阅读文字。

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

答案 6 :(得分:1)

听取专家的意见和Don't roll your own CSV parser

您首先想到的是,“我如何处理新的换行符?”

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

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

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

答案 7 :(得分:1)

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

答案 8 :(得分:0)

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

答案 9 :(得分:0)

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

答案 10 :(得分:0)

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

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

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

答案 11 :(得分:0)

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 => a.n / 3);

答案 12 :(得分:0)

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

答案 13 :(得分:0)

您还可以在NuGet上签出我的CSV解析器SoftCircuits.CsvParser。它不仅可以解析CSV文件,而且还可以(如果需要)自动将列值映射到您的类属性。它的运行速度比CsvHelper快四倍。

答案 14 :(得分:0)

要在 CSV 中存在换行符,必须有一个未关闭的开放双引号。 假设所有 CSV 单元格必须打开和关闭双引号,只需检查是否有奇数个引号

my_string.Count(c => c == '"') % 2 == 1

如果是这样,请继续阅读,直到您获得偶数。