2012-10-24 21 views
6

Tôi có một số tệp Csv thực sự bị lỗi mà tôi cần phân tích cú pháp. Tôi đang sử dụng CsvHelper và nó đang làm việc tuyệt vời. Ngoại trừ tôi có một số dòng có khoảng trống nơi normaly tôi có một đôi.Sử dụng CsvHelper tôi có thể dịch không gian trắng thành giá trị rỗng không?

File:

Text, SomeDouble, MoreText

"Good", 1,23, "Good"

"Bad", "Bad"

nếu tôi hãy thử và ánh xạ bản đồ này vào

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

sau đó tôi nhận được một lỗi như thế này:

CsvHelper.CsvReaderException: Một lỗi đã xảy ra cố gắng để đọc một kỷ lục loại

Row: '2' (1-based)

Dòng Index: '1' (dựa trên 0)

Tên trường: Giá trị

Dòng 'SomeDouble': ''

System.Exception: không phải là giá trị hợp lệ cho Double. ---> System.FormatException: Chuỗi đầu vào không đúng định dạng.
tại System.Number.ParseDouble (String giá trị, tùy chọn NumberStyles, NumberFormatInfo numfmt) tại System.ComponentModel.DoubleConverter.FromString (String value, NumberFormatInfo formatInfo) tại System.ComponentModel.BaseNumberConverter.ConvertFrom (ITypeDescriptorContext bối cảnh, CultureInfo văn hóa, giá trị Object) --- End của nội ngoại lệ stack trace --- tại System.ComponentModel.BaseNumberConverter.ConvertFrom (ITypeDescriptorContext bối cảnh, văn hóa CultureInfo, giá trị Object) tại System.ComponentModel.NullableConverter.ConvertFrom (ITypeDescriptorContext ngữ cảnh, văn hóa CultureInfo, Giá trị đối tượng) tại lambda_method (Đóng cửa, ICsvReader) tại CsvHelper.CsvReader.d__0`1.MoveNext()

Như tôi đã nhìn thấy nó, lựa chọn của tôi là để tạo ra một phân tích cú pháp tùy chỉnh, hoặc bản đồ giá trị của tôi vào một tài sản chuỗi và làm phân tích ở đó.

Có tùy chọn nào khác không?

Sẽ rất tuyệt nếu tôi có thể định cấu hình rằng tôi muốn xử lý khoảng trắng là rỗng.

Theo yêu cầu, đây là một mẫu mã nhằm tái tạo vấn đề

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'... 
      } 
    } 

Cảm ơn.

+0

Bạn có thể đăng bài c ode cho phương pháp thực sự thất bại, tôi không quen với CSVHelper. –

+0

Tôi đã chỉnh sửa câu hỏi với một ví dụ tốt hơn – RMK

+0

Tôi không nghĩ rằng nó không có gói, nhưng điều này có giúp ích không: [tùy chỉnh typeconverter] (https://github.com/JoshClose/CsvHelper/wiki/Custom-TypeConverter) Tôi sẽ xem nếu tôi nhận được bất cứ nơi nào với nó, tôi có thể sử dụng tính năng đó quá. Vui lòng đăng nếu bạn tìm thấy giải pháp. –

Trả lời

6

Cuối cùng, tôi đã tạo bộ chuyển đổi kiểu của riêng mình để xử lý khoảng trắng giống như một giá trị rỗng.

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

Áp dụng nó để mô hình của bạn như thế này

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

Một cách đơn giản là sử dụng ConvertUsing() trong ClassMap của bạn:

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

Tôi muốn thực hiện chức năng helper ít và cuộc gọi họ

Map(x => x.SomeDouble) 
    .ConvertUsing(row => GetOddballDouble(row.GetField("SomeDouble"))); 
Các vấn đề liên quan