2012-10-24 229 views
6

私はパーズする必要がある実際には駄目なCsvファイルがあります。私はCsvHelperを使用していて、すごくうまくいっています。私は普通の場所に空白を持った行をいくつか持っています。CsvHelperを使用すると、空白をNULLに変換できますか?

ファイル:

テキスト、SomeDouble、moreTextの

"グッド"、1.23、 "グッド"

、 "悪い" "悪い"

もし私がこれをマップして

public class Test 
{ 
    [CsvField(Name = "Text")] 
    public string Text { get; set; } 

    [CsvField(Name = "SomeDouble")] 
    public double? SomeDouble{ get; set; } 

    [CsvField(Name = "MoreText")] 
    public string MoreText{ get; set; } 
} 
にマップしてください

その後、私はこのようなエラーが出る:

CsvHelper.CsvReaderException: '2'(1ベース)

フィールド:エラーがタイプ

行の レコードを読み取るしようとして発生しましたインデックス '1'(0系)

フィールド名: 'SomeDouble'

フィールド値: ''

System.Exception:Doubleの有効な値ではありません。 ---> System.FormatException:入力文字列の形式が正しくありませんでした。 System.ComponentModel.BaseNumberConverter.ConvertFrom(ITypeDescriptorContext 文脈でSystem.ComponentModel.DoubleConverter.FromString(String値、 するNumberFormatInfo formatInfo)でSystem.Number.ParseDoubleで
(文字列値、NumberStylesオプション、 するNumberFormatInfo numfmt) System.ComponentModel.NullableConverter.ConvertFrom(ITypeDescriptorContextで System.ComponentModel.BaseNumberConverter.ConvertFrom(ITypeDescriptorContext コンテキスト、CultureInfoカルチャ、オブジェクト値)の内 例外スタックトレースのCultureInfoカルチャ、オブジェクト値)---終わり--- コンテキスト、CultureInfoカルチャ、オブジェクト値) lambda_method私はそれを見ると、私のオプションは、カスタムパーサーを作成する、または文字列プロパティに私の値をマッピングしており、やる

CsvHelper.CsvReader.d__0`1.MoveNext()で(閉鎖、ICsvReader)そこでの解析。

その他のオプションはありますか?

空白をnullとして処理するように設定できるといいですね。要求されたよう

、ここで問題

static class Program 
    { 
     public class Test 
     { 
      [CsvField(Name = "Text")] 
      public string Text { get; set; } 

      [CsvField(Name = "SomeDouble")] 
      public double? SomeDouble { get; set; } 

      [CsvField(Name = "MoreText")] 
      public string MoreText { get; set; } 
     } 

     static void Main(string[] args) 
     { 
      // create fake in memory file 
      var memoryStream = new MemoryStream(); 
      var streamWriter = new StreamWriter(memoryStream); 
      streamWriter.WriteLine("Text,SomeDouble,MoreText"); 
      streamWriter.WriteLine("Good, 1.23, Good"); 
      streamWriter.WriteLine("Bad, ,Bad"); 

      streamWriter.Flush(); 

      //reset the file to the begining 
      memoryStream.Position = 0; 

      using (
       var csv = 
        new CsvReader(
         new StreamReader(memoryStream))) 
      { 
       // this call will blow up with the exception. 
       var records = csv.GetRecords<Test>().ToList(); 

       //carry on and do stuff with 'records'... 
      } 
    } 

感謝を再現するコードサンプルがあります。

+0

私はCSVHelperに慣れていません。 –

+0

私は良い例を使って質問を編集しました – RMK

+0

私はそれを行うパッケージがないとは思わないが、これは役に立ちますか?[custom typeconverter](https://github.com/JoshClose/CsvHelper/wiki)/Custom-TypeConverter)私はそれをどこにでも持っているかどうかを調べるつもりです。あなたが解決策を見つけたら投稿してください。 –

答えて

6

最後に、空白をnullと同じように扱う独自の型変換プログラムを作成しました。私は少しヘルパー関数とコールをしたいと

Map(x => x.SomeDouble) 
    .ConvertUsing(row => 
     string.IsNullOrWhiteSpace(row.GetField("SomeDouble")) ? 
      (double?) null : 
      Convert.ToDouble(row.GetField("SomeDouble"))); 

public class WhiteSpaceToNullableTypeConverter<T> : TypeConverter where T : struct 
{ 
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) 
    { 
     return sourceType == typeof (string); 
    } 

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) 
    { 
     return destinationType == typeof (T?); 
    } 

    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, 
             object value) 
    { 
     T? result = null; 

     var stringValue = (string) value; 
     if (!string.IsNullOrWhiteSpace(stringValue)) 
     { 
      var converter = TypeDescriptor.GetConverter(typeof(T)); 
      result = (T)converter.ConvertFrom(stringValue.Trim()); 
     } 

     return result; 
    } 

    public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, 
            object value, Type destinationType) 
    { 
     var result = (T?) value; 
     return result.ToString(); 
    } 
} 

は簡単な方法は、あなたのClassMapでConvertUsing()を使用することで、この

public class Test 
{ 
    [CsvField(Name = "Text")] 
    public string Text { get; set; } 

    [CsvField(Name = "SomeDouble")] 
    [TypeConverter(typeof(WhiteSpaceToNullableTypeConverter<Double>))] 
    public double? SomeDouble{ get; set; } 

    [CsvField(Name = "MoreText")] 
    public string MoreText{ get; set; } 
} 
3

のようなあなたのモデルにそれを適用しますそれら

Map(x => x.SomeDouble) 
    .ConvertUsing(row => GetOddballDouble(row.GetField("SomeDouble"))); 
関連する問題