こんな csv を扱う必要がありまして。
Tanaka,38 Kazuki,NULL Kazuakix,98 muu,NULL
null が入ってるところには丁寧に文字列で NULL と記載されています。 こういう csv を見るたびにデータ部分に NULL っていう文字列データつっこんだらどうするんだろうと思ってしまう今日この頃です。 今回の例は、数字の列なので、そういういたずらは出来ませんが。
ということで個人的に C# で CSV を扱う時によくつかってる CsvHelper でのやりかたです。
ドキュメント的にはここらへんですね。
ClassMap というクラスを使ってクラスと csv のマッピングをカスタマイズできるのですが、ここで TypeConverter というのをかませることが出来ます。 ということで、今回の場合はこういう TypeConverter を作って…。
class NullableIntConverter : ITypeConverter { public object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData) { return text == "NULL" ? null : (int?)int.Parse(text); // 数字じゃないデータきたら潔く死ぬ } public string ConvertToString(object value, IWriterRow row, MemberMapData memberMapData) { throw new NotImplementedException(); // 今回は読込だけなので、こっちは実装しない。 } }
そして、こんな感じにクラスと ClassMap を作ります。
class Record { public string Name { get; set; } public int? Age { get; set; } } class RecordMap : ClassMap<Record> { public RecordMap() { this.AutoMap(); this.Map(x => x.Age).TypeConverter<NullableIntConverter>(); } }
では、さっそく試してみましょう。
namespace CSVHelperLab { class Program { static void Main(string[] args) { var csv = @"Tanaka,38 Kazuki,NULL Kazuakix,98 muu,NULL"; using (var p = new CsvReader(new StringReader(csv))) { p.Configuration.HasHeaderRecord = false; p.Configuration.RegisterClassMap<RecordMap>(); var records = p.GetRecords<Record>(); foreach (var record in records) { Console.WriteLine($"{record.Name}: {record.Age}"); } } } } }
実行するとこうなります。
Tanaka: 38 Kazuki: Kazuakix: 98 muu:
いい感じですね。