web-dev-qa-db-ja.com

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]の位置にある;を確認しました。 trueの場合は書き込み、falseの場合は最後に追加*改行を削除)

ファイルをtxtとして保存しているため、問題が発生しています。

ちなみに、excellにcsvとして保存してexcellspreadshitをcsvに変換しています。しかし、クライアントがそれを行っているかどうかはわかりません。

したがって、a 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();


        }




        }
    } 
12
user144658

CSVには、それを処理するための事前定義された方法があります。このサイトでは、標準の読みやすい説明を提供しています CSVのすべての警告を処理する方法

それでも、CSVファイルの読み取りと書き込みに堅実なオープンソースライブラリを使用しない理由は実際にはありません。これは、標準外の間違いを避けるためです。 LINQtoCSV は、このための私のお気に入りのライブラリです。クリーンでシンプルな方法での読み取りと書き込みをサポートします。

または、 this SO CSVライブラリに関する質問 で最も人気のある選択肢のリストが表示されます。

14
Michael La Voie

現在の行に最初の文字として( ")がないかどうかを確認するのではなく、代わりに最後の文字が(")であるかどうかを確認してください。そうでない場合は、改行があることがわかり、次の行を読み取ってマージできます。

サンプルデータは正確であると想定しています。フィールドは引用符で囲まれています。引用符でテキストフィールドが区切られない場合(またはテキスト以外のデータに新しい行が含まれている場合)、すべての賭けは無効になります。

5
Doug

.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
Michael

最近、このコードを使用して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!
    }
2
Zoman

たぶん、ReadLine()の間に( ")を数えることができます。それらが奇数の場合、フラグが立てられます。これらの行を無視するか、次の2つを取得して、マージ行の最初の"\n "オカレンスを削除することができます。 。

1
Freddy

私が通常行うことは、この非常に問題があるため、行ごとではなく文字ごとにテキストを読むことです。

各文字を読んでいると、各セルの開始位置と停止位置だけでなく、行とセルの改行の違いも理解できるはずです。正しく覚えていれば、Excelで生成されたファイルの場合、行は開始します。\r\nで、セルの改行は\ rのみです。

1
John

専門家からのアドバイスに注意してください 独自のCSVパーサーをロールしないでください

あなたの最初の考えは、「改行をどのように処理するか」です。

次の考えは、「引用符内のコンマを処理する必要がある」です。

次の考えは、「ああ、がらくた、引用符の内側で引用符を処理する必要があります。エスケープされた引用符。二重引用符。一重引用符...」です。

それは狂気への道です。自分で書いてはいけません。すべての難しい部分に当てはまり、あなたのために地獄を通り抜けた、広範なユニットテストカバレッジを備えたライブラリを見つけてください。 .NETの場合は、 無料のFileHelpersライブラリ を使用します。

CsvHelper (私が管理しているライブラリ)を試してください。空の行は無視されます。 FastCsvReaderで設定できるフラグがあり、空の行も処理できると思います。

1
Josh Close

ご覧ください FileHelpers Library 改行付きのCSVの読み取り/書き込みとExcelへの読み取り/書き込みをサポートしています

0
fergal

パーサーの例として、ケースを正しく処理しているように見えるc#があります。次に、データを読み込み、読み取り後に改行を削除します。 パート2 はパーサーであり、ライター部分をカバーする パート1 があります。

0
Doug

行を読んでください。
列(フィールド)に分割します。
各行に十分な列が必要な場合は、処理します。
そうでない場合は、次の行を読み、必要なものが得られるまで残りの列をキャプチャします。
繰り返す。

0
FlappySocks

やや単純な正規表現を各行で使用できます。一致する場合は、一致する各フィールドを処理します。一致するものが見つからない場合は、その行をスキップします。

正規表現は次のようになります。

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.
  }
}
0
John Fisher

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);
0