RMK*_*RMK 8 .net c# csv parsing csvhelper
我有一些非常蹩脚的Csv文件我需要解析.我正在使用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; }
}
Run Code Online (Sandbox Code Playgroud)
然后我得到这样的错误:
CsvHelper.CsvReaderException:尝试读取类型记录时发生错误
行:'2'(从1开始)
场指数:'1'(基于0)
字段名称:'SomeDouble'
场地价值:''
System.Exception:不是Double的有效值.---> System.FormatException:输入字符串的格式不正确.
处于System.ComponentModel.DoubleConverter.FromString(String value,NumberFormatInfo formatInfo)的System.Number.ParseDouble(String value,NumberStyles options,NumberFormatInfo numfmt),位于System.ComponentModel.BaseNumberConverter.ConvertFrom(ITypeDescriptorContext context,CultureInfo culture,Object value) - - 内部异常堆栈跟踪的结束---在lambda_method的System.ComponentModel.NullableConverter.ConvertFrom(ITypeDescriptorContext context,CultureInfo culture,Object value)处的System.ComponentModel.BaseNumberConverter.ConvertFrom(ITypeDescriptorContext context,CultureInfo culture,Object value)处闭包,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'...
}
}
Run Code Online (Sandbox Code Playgroud)
谢谢.
最后,我创建了自己的类型转换器,将空白与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();
}
}
Run Code Online (Sandbox Code Playgroud)
像这样将它应用到您的模型中
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; }
}
Run Code Online (Sandbox Code Playgroud)
一种简单的方法是在ClassMap中使用ConvertUsing():
Map(x => x.SomeDouble)
.ConvertUsing(row =>
string.IsNullOrWhiteSpace(row.GetField("SomeDouble")) ?
(double?) null :
Convert.ToDouble(row.GetField("SomeDouble")));
Run Code Online (Sandbox Code Playgroud)
我喜欢制作小辅助函数并调用它们
Map(x => x.SomeDouble)
.ConvertUsing(row => GetOddballDouble(row.GetField("SomeDouble")));
Run Code Online (Sandbox Code Playgroud)