LoginSignup

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

"(ダブルクオーテーション)を含んだCSVを、CSVReaderを用いて読み込む

解決したいこと

C#を勉強しています。
C#のWindowsFormで、CSVファイルを読み込むんで表示するプログラムを作っています。
CSVの読み込みにはCSVHelperというライブラリが有用との情報を得て、CSVHelper(ver27)を利用しています。

CSVデータにダブルクオーテーションがない場合は読み込めたのですが、CSVデータにダブルクオーテーションがあると読み込めません。以下のエラーメッセージが出現します。

発生している問題・エラー

キャプチャ.PNG

該当するソースコード

C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using CsvHelper;
using CsvHelper.Configuration;
using CsvHelper.Configuration.Attributes;
using System.IO;
using System.Globalization;

namespace CSVReadForm4
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            List<S> records;

            using (var streamReader = new StreamReader(@"ファイルパス"))
            using (var csvReader = new CsvReader(streamReader, CultureInfo.InvariantCulture))
            {
                records = csvReader.GetRecords<S>().ToList();
            }
            dataGridView1.DataSource = records;
        }
    }
    public class S
    {
        [Name("AAA")]
        public string aaa { get; set; }
        [Name("BBB")]
        public string bbb { get; set; }
        [Name("CCC")]
        public long ccc { get; set; }
        [Name("DDD")]
        public DateTime ddd { get; set; }
    }
}

### 自分で試したこと
CSVHelperのConfigurationの設定でなんとかならないか試しましたが、うまくいきませんでした。
ダブルクオーテーションは取り除かれてしまってもかまいません。どなたかご教示をお願いします。
0

5Answer

CSVでダブルクォーテーションを使用する場合はエスケープしなければいけません

勘定科目コード,補助科目コード,当月残高(機能通貨),GL記帳日,メモ
1234567890,100,1,8月13日,あいうえお
1234567890,100,1,8月13日,あいうえお"かきくけこ"

この例であれば

1234567890,100,1,8月13日,"あいうえお""かきくけこ"""

こうしなければ不正なデータと判定されてしまうと思います

1Like

Comments

  1. @yukatanoyutaka

    Questioner
    返事が遅くなってしまい申し訳ありません、またご回答ありがとうございます。
    あれからいろいろ試してみましたが、やはりご指摘のとおり、ダブルクオーテーションがある(RFC4180に準拠していない)とCSVHelperでは読み込みできないようです。

    ご指摘をうけ、とりあえずは使わない作戦で乗り切ることにしました。ありがとうございました。
This answer has been deleted for violation of our Terms of Service.
This answer has been deleted for violation of our Terms of Service.

CSVに不正なデータが検出されたというエラーです。
エラーしたCSVを見せていただくことは可能でしょうか?

メモ

0Like

Comments

  1. @yukatanoyutaka

    Questioner
    ありがとうございます。また返信が遅くなってしまい申し訳ありません。
    こんな感じで"(ダブルクオーテーション)が入っているレコード(下のレコード)でエラーがでています。

    勘定科目コード,補助科目コード,当月残高(機能通貨),GL記帳日,メモ
    1234567890,100,1,8月13日,あいうえお
    1234567890,100,1,8月13日,あいうえお"かきくけこ"


    もう少しいろいろ調べて、他にも同じように困っている人の投稿をみつけました。
    http://5.9.10.113/67835079/how-to-handle-quotation-mark-in-data-when-using-csvhelper
    https://stackoverflow.com/questions/66824728/custom-delimiter-doesnt-work-in-csvhelper

    Mode = CsvMode.NoEscapeを加えても、やはり同じところでエラーが起きてしまいました。ダブルクオーテーションが含まれる文字列をCSVHelperで読み取ることは不可能なんですかね。
  2. CsvHelperは使ったことがないのですが、CsvHelperのサイトには「RFC4180準拠」とありますし、RFC4180では二重引用符の使用が規定されています。
    素直に受け取れば、二重引用符を使用したCSVがサポートされているはずです。

    また、「CSVに不正なデータが検出された」というエラーが報告されているのですから、対象のCSVファイルがRFC4180に反する可能性が高いと考えられます。
    報告されている`ColumnCount: 0`、`CurrentIndex: 19`というのは「19行目の最初の列」ではないでしょうか。
    その辺りで、RFC4180に違反する書式を探してみるのはいかがでしょうか。

    あるいは、本番データの代わりに、同様のエラーを生じる最小限のCSVファイルをダミーデータで生成することはできないでしょうか。


  3. @yukatanoyutaka

    Questioner
    ご回答いただきありがとうございます、また返信が遅くなってしまい申し訳ありません。
    恥ずかしながら、今回RFC4180という規格の存在を初めて知ることができました。ご教示いただきありがとうございます。

    いろいろ試してみましたが、ダブルクオーテーション付のCSVはRFC4180に準拠していないということで、CSVHelperのサポート対象外のようです。とりあえず今回はCSVHelperを使わない作戦で乗り切ることにしました。ありがとうございました。

読もうとしているCSVファイルがRFC4180に反していることはわかっていて、引用符をすべて無視してでもいいからそのファイルを読み込みたいという話だと思います。

リファレンスマニュアル的なものが用意されていないのでCSVHelperでどうすればいいかわかりませんが、それならファイルの内容を加工してからCSVHelperに渡すという作戦もあります。

    /// <summary>
    /// 元ストリームから二重引用符を除去したストリーム
    /// </summary>
    /// <remarks>ASCIIまたはUTF-8エンコードしか考慮していない</remarks>
    public class DQuoteRemoveStream : System.IO.MemoryStream
    {
        private const byte DQUOTE = (byte)'"';
        public DQuoteRemoveStream(System.IO.Stream sourceStream) : base((int)sourceStream.Length)
        {
            var buffer = new byte[8192];
            int readbytes;
            int st = 0, len=0;
            while ((readbytes = sourceStream.Read(buffer)) > 0)
            {
                while (st + len < readbytes)
                {
                    if (buffer[st + len] != DQUOTE)
                    { len++; }
                    else
                    {
                        if (len > 0)
                        { this.Write(new ReadOnlySpan<byte>(buffer, st, len)); }
                        st += len + 1;
                        len = 0;
                    }
                }
            }
            if (len > 0)
            { this.Write(new ReadOnlySpan<byte>(buffer, st, len)); }
            this.SetLength(st + len);
            this.Seek(0, System.IO.SeekOrigin.Begin);
        }
    }

動作確認していませんが、CSVHelperに渡すストリームをこれにすれば
効率は悪いけどCSVHelperの設定に悩むよりは手っ取り早いかと思います。

0Like

Comments

  1. @yukatanoyutaka

    Questioner
    ご回答いただきありがとうございます。はい、まさに「読もうとしているCSVファイルがRFC4180に反していることはわかっていて、引用符をすべて無視してでもいいからそのファイルを読み込みたいという話」でした。

    なるほど、あらかじめ別のクラスでダブルクオーテーションを除去しておけばいいんですね。CSVHelperを使えばシンプルにCSV読み込みできるようなので、多少汚いファイルでもこれを使いこなせるようになりたいです。

    ソースコードもありがとうございます。とりあえずはCSVHelperの使用をあきらめていたのですが、こちらのクラスも試してみます。ありがとうございました!

Your answer might help someone💌