山口屋~活動日誌~

私生活で主な出来事をピックアップ

CSVファイル C# TextFieldParser 文字列 構文解析 MemoryStream

2023-11-21 12:45:49 | ソフトウェア開発
Comma-Separated Values (CSV) の標準仕様としては下記がある。
RFC4180 : Common Format and MIME Type for Comma-Separated Values (CSV) Files
解説は様々なサイトがあるが下記の例は簡潔で、スペースや空白についての説明が他では無いことが多いので参考になった。
知識データベース:CSVフォーマット
・RFC準拠:前後にスペースがあっても無視しない
・RFC未定義:ダブルクォーテーションで囲まれているフィールドの前後に空白がある

CSVファイルの入力を行うのであれば、VB.NET用のTextFieldParserクラスを利用するのが楽だ。
・.NET Tips (VB.NET,C#...):CSV形式のファイルをDataTableや配列等として取得する

TextFieldParserクラス(Microsoft.VisualBasic.FileIO名前空間)は.NET Framework 2.0以降のVisualBasic用の機能として用意され、C#でも参照設定でMicrosoft.VisualBasic.dllを追加することが可能で、CSV(Comma-Separated Values)ファイルの解析でよく利用されるが、文字列の解析にも利用することができる。

ダブルクォーテーション中であっても空行は読み飛ばす点に注意。
Microsoft Docs:TextFieldParser.ReadFields メソッド (Microsoft.VisualBasic.FileIO)
TrimWhiteSpaceプロパティは、trueにするとダブルクォーテーション中でも前後の空白文字が削除されてしまうので、falseにすべき?

TextFieldParserを使う方法同士で速度を比較したサイトがある。
tabelog2001 - Qiita:【C#】TextFieldParserで100万行のCSVファイルに挑む。
上記サイトの実験例では下記の方法が最速であった。
・File.ReadAllLines.Lengthで、行数を取得
・MemoryStreamクラスで、File.ReadAllLinesの各要素(1行)単位で入力
・TextFieldParserクラスも、MemoryStreamに対応して、1行単位で処理
最も結果に影響したのは、反復処理にforeachを使用しないことであったようだ。
MemoryStreamクラスには、StreamReader.ReadLine()でも1行単位の入力が可能。
なお、Streamの派生クラスの中でもMemoryStreamクラスのようなシーク可能クラスはReadメソッド等で読取しただけではメモリ解放されないので注意。

タブ区切りの場合は、TextFieldParser.SetDelimitersにタブを指定すればよい。

スペース区切りの場合は、TextFieldParserクラスではなくString.Splitを使い、必要に応じてStringSplitOptions.RemoveEmptyEntriesを指定するとよい。

TextFieldParserクラスのコンストラクタ:TextFieldParser(TextReader reader)は、引数にTextReaderクラス(System.IO名前空間)を取ることができるので、TextReaderクラスの派生クラスである、StreamReaderクラス、StringReaderクラスも引数に取ることができる。

TextFieldParserクラスのコンストラクタで、StringReaderクラスを引数に取れば、文字列の解析にも利用できる。

<用語集>

字句解析器
・スキャナ(scanner)
・トークナイザ(tokenizer)

構文解析器
・パーサ(parser)


最新の画像もっと見る

コメントを投稿