我有一些非常蹩脚的CSV文件我需要解析。我使用CsvHelper并且工作真棒。除非我有一些线路有空白的地方normaly我有一个双。
I have some really lame Csv files I need to parse. I am using CsvHelper and it is working awesome. Except I have some lines that have whitespace where normaly I have a double.
文件:
文本,SomeDouble,MoreText
Text,SomeDouble,MoreText
好,1.23好
坏,坏
如果我试图映射到这一点
if I try and map this into
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; }
}
然后我得到一个错误这样的:
then I get an error like this:
CsvHelper.CsvReaderException:出错试图读取一个 类型的记录
CsvHelper.CsvReaderException: An error occurred trying to read a record of type
行:'2'(1型)
字段索引:'1'(从0开始)
Field Index: '1' (0-based)
字段名称:SomeDouble
Field Name: 'SomeDouble'
字段值:
System.Exception的:不是双有效值。 ---> 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(封闭,ICsvReader)在 CsvHelper.CsvReader.d__0`1.MoveNext()
System.Exception: is not a valid value for Double. ---> System.FormatException: Input string was not in a correct format. at System.Number.ParseDouble(String value, NumberStyles options, NumberFormatInfo numfmt) at System.ComponentModel.DoubleConverter.FromString(String value, NumberFormatInfo formatInfo) at System.ComponentModel.BaseNumberConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value) --- End of inner exception stack trace --- at System.ComponentModel.BaseNumberConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value) at System.ComponentModel.NullableConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value) at lambda_method(Closure , ICsvReader ) at CsvHelper.CsvReader.d__0`1.MoveNext()
在我看来,我的选择是创建一个自定义的解析器,或者我的价值映射到一个字符串属性,做解析那里。
As I see it, my options are to create a custom parser, or map my value into a string property and do the parsing there.
是否还有其他选择吗?
这将是很好,如果我能配置,我想对待空白为空。
It would be nice if I could configure that I want to treat white space as null.
根据要求,这里是一个code样品能重现问题
As requested, here is a code sample that reproduces the problem
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'...
}
}
感谢。
在最后,我去与创建我自己的类型转换器,它会将空白字符等同于零。
In the end I went with creating my own type converter that will treat whitespace the same as a 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();
}
}
它应用到你的模型像这样
Apply it to your model like this
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; }
}