8

解析する必要がある非常に不十分な Csv ファイルがいくつかあります。私は CsvHelper を使用していますが、うまく機能しています。ただし、通常は二重の空白がある行がいくつかあります。

ファイル:

Text,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.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 カルチャ、オブジェクト値) で lambda_method( Closure 、 ICsvReader ) CsvHelper.CsvReader.d__0`1.MoveNext() で

私の考えでは、カスタム パーサーを作成するか、値を文字列プロパティにマップしてそこで解析を行うという選択肢があります。

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

空白を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'...
            }
    }

ありがとう。

4

2 に答える 2

6

最後に、空白をヌルと同じように扱う独自の型コンバーターを作成しました。

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; }
}
于 2012-10-29T13:37:04.420 に答える