2012-10-24 73 views
6

我有一些非常蹩腳的Csv文件需要解析。我正在使用CsvHelper,它工作的很棒。除了我有一些有空格的行,在正常情況下我有雙行。使用CsvHelper可以將白色空間翻譯爲可空?

文件:

文本,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)

場(從0開始) '1'

字段名稱::索引 'SomeDouble'

字段值: ''

System.Exception:不是Double的有效值。 ---> System.FormatException:輸入字符串格式不正確。
在System.Number.ParseDouble(字符串值,的NumberStyles選項, 的NumberFormatInfo numfmt)在 System.ComponentModel.DoubleConverter.FromString(字符串值, 的NumberFormatInfo formatInfo)在 System.ComponentModel.BaseNumberConverter.ConvertFrom(ITypeDescriptorContext 上下文中,的CultureInfo文化,對象的值)---內 異常堆棧跟蹤的末尾在 System.ComponentModel.BaseNumberConverter.ConvertFrom(ITypeDescriptorContext 上下文,CultureInfo的文化,對象值) System.ComponentModel.NullableConverter.ConvertFrom(ITypeDescriptorContext 上下文,CultureInfo culture,Object value)在 lambda_method(封閉,ICsvReader)在 CsvHelper.CsvReader.d__0`1.MoveNext()

在我看來,我的選擇是創建一個自定義的解析器,或者我的值映射到一個字符串屬性,做在那裏解析。

還有其他的選擇嗎?

這將是很好,如果我可以配置,我想把空白爲空。

按照要求,這裏是能重現問題

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

你可以發佈c對於實際失敗的方法,我不熟悉CSVHelper。 –

+0

我編輯了一個更好的例子的問題 – RMK

+0

我不認爲它是那樣的包,但是這有助於:[自定義typeconverter](https://github.com/JoshClose/CsvHelper/wiki/Custom-TypeConverter)我將會看看我是否能夠使用它,我也可以使用該功能。如果您找到解決方案,請發佈。 –

回答

6

最後,我創建了我自己的類型轉換器,它將空白視爲null。

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(); 
    } 
} 

它應用到你的模型像這樣

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

一種簡單的方法是在你的類映射使用ConvertUsing():

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

我喜歡做小幫手功能和呼叫他們

Map(x => x.SomeDouble) 
    .ConvertUsing(row => GetOddballDouble(row.GetField("SomeDouble")));