Trim 读取前的值
Trim value before reading
我有一个 csv,我需要在一列中读取它包含一个整数值,但是值后面有一个 space,所以 csv 中的值为 "1,264 "
。
在class我有
public int MyValue { get; set; }
但是当我尝试读取记录时出现以下错误:
TypeConverterException: The conversion cannot be performed.
Text: '1,264 '
MemberType: System.Int32
TypeConverter: 'CsvHelper.TypeConversion.Int32Converter' IReader state: ColumnCount: 0 CurrentIndex: 26 HeaderRecord:
显然我需要 trim 字段中的空白 space。我无法控制初始格式的格式。
我可以把它变成一个字符串 属性 并在第二遍解析它,但我想看看是否有其他方法。
更新
我尝试删除 space,但仍然出现错误。我以为这可能是一个文化信息问题,当我阅读时,我有以下代码:
using (var reader = new StreamReader(@"C:\temp\file.csv"))
using (var csv = new CsvReader(reader, new CsvConfiguration(new CultureInfo("en-US")) {
TrimOptions = TrimOptions.Trim
})) {...}
更新 2
考虑一个包含 header 且单列单行(除了 header 之外)的文件:
MyValue
"1,264 "
更新 3
我当前的语言环境规定逗号是小数分隔符,小数点是千位分隔符。
因此,正如评论中已经提到的那样,1.264
是一个 double
并且尝试将其解析为整数将引发异常。并且额外的 space 在默认的 CSV 配置中不是问题:
public static class Program
{
static void Main(string[] args)
{
var csvContent = @"Id,Value
1,""1.236 """;
List<Entry> entries;
using (var reader = new StringReader(csvContent))
using (var csvReader = new CsvReader(reader, CultureInfo.GetCultureInfo("en-us")))
{
entries = csvReader.GetRecords<Entry>().ToList();
}
foreach (var entry in entries)
{
Console.WriteLine($"{entry.Id} {entry.Value}");
}
}
}
public class Entry
{
public int Id { get; set; }
public double Value { get; set; }
}
我能够在不使用 TypeConverter
将 int 声明更改为 double 的情况下解决问题
步骤如下:
首先创建类型转换器class
public class TestClass
{
public int Value { get; set; }
}
public class IntegerWithGroupSeparatorConverter: CsvHelper.TypeConversion.ITypeConverter
{
public string ConvertToString(object value, IWriterRow row, MemberMapData mpd)
{
return value?.ToString();
}
public object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
{
if(Int32.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out int result))
return result;
else
return 0; // Not sure if 0 is acceptable or not
}
}
public class TestMap : ClassMap<Test>
{
public TestMap()
{
Map(m => m.Value).TypeConverter<IntegerWithGroupSeparatorConverter>();
}
}
现在我们可以用这个
为您的阅读代码提供这个类型转换器
List<TestClass> entries;
CultureInfo ci = new CultureInfo("en-us");
using (var reader = new StringReader(csvContent))
using (var csvReader = new CsvReader(reader, ci))
{
csvReader.Context.RegisterClassMap<TestMap>();
entries = csvReader.GetRecords<TestClass>().ToList();
}
我深入研究了源代码并找到了解决方案。
如果您检查 Int32Converter 的来源,您可能会看到,它使用成员中定义的 NumberStyles 作为属性进行转换,或者获取整数的默认值。
当我将 NumberStyles 属性设置为 Number 时,它无需任何其他更改即可正常工作。我更喜欢这个解决方案,因为我不必更改 属性.
的预期类型
所以我只需要将 class 定义更改为:
public class TestClass
{
[Name("MyValue"), CsvHelper.Configuration.Attributes.Optional, NumberStyles(NumberStyles.Number)]
public int MyValue { get; set; }
}
我有一个 csv,我需要在一列中读取它包含一个整数值,但是值后面有一个 space,所以 csv 中的值为 "1,264 "
。
在class我有
public int MyValue { get; set; }
但是当我尝试读取记录时出现以下错误:
TypeConverterException: The conversion cannot be performed. Text: '1,264 ' MemberType: System.Int32 TypeConverter: 'CsvHelper.TypeConversion.Int32Converter' IReader state: ColumnCount: 0 CurrentIndex: 26 HeaderRecord:
显然我需要 trim 字段中的空白 space。我无法控制初始格式的格式。
我可以把它变成一个字符串 属性 并在第二遍解析它,但我想看看是否有其他方法。
更新
我尝试删除 space,但仍然出现错误。我以为这可能是一个文化信息问题,当我阅读时,我有以下代码:
using (var reader = new StreamReader(@"C:\temp\file.csv"))
using (var csv = new CsvReader(reader, new CsvConfiguration(new CultureInfo("en-US")) {
TrimOptions = TrimOptions.Trim
})) {...}
更新 2
考虑一个包含 header 且单列单行(除了 header 之外)的文件:
MyValue
"1,264 "
更新 3
我当前的语言环境规定逗号是小数分隔符,小数点是千位分隔符。
因此,正如评论中已经提到的那样,1.264
是一个 double
并且尝试将其解析为整数将引发异常。并且额外的 space 在默认的 CSV 配置中不是问题:
public static class Program
{
static void Main(string[] args)
{
var csvContent = @"Id,Value
1,""1.236 """;
List<Entry> entries;
using (var reader = new StringReader(csvContent))
using (var csvReader = new CsvReader(reader, CultureInfo.GetCultureInfo("en-us")))
{
entries = csvReader.GetRecords<Entry>().ToList();
}
foreach (var entry in entries)
{
Console.WriteLine($"{entry.Id} {entry.Value}");
}
}
}
public class Entry
{
public int Id { get; set; }
public double Value { get; set; }
}
我能够在不使用 TypeConverter
将 int 声明更改为 double 的情况下解决问题步骤如下:
首先创建类型转换器class
public class TestClass
{
public int Value { get; set; }
}
public class IntegerWithGroupSeparatorConverter: CsvHelper.TypeConversion.ITypeConverter
{
public string ConvertToString(object value, IWriterRow row, MemberMapData mpd)
{
return value?.ToString();
}
public object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
{
if(Int32.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out int result))
return result;
else
return 0; // Not sure if 0 is acceptable or not
}
}
public class TestMap : ClassMap<Test>
{
public TestMap()
{
Map(m => m.Value).TypeConverter<IntegerWithGroupSeparatorConverter>();
}
}
现在我们可以用这个
为您的阅读代码提供这个类型转换器List<TestClass> entries;
CultureInfo ci = new CultureInfo("en-us");
using (var reader = new StringReader(csvContent))
using (var csvReader = new CsvReader(reader, ci))
{
csvReader.Context.RegisterClassMap<TestMap>();
entries = csvReader.GetRecords<TestClass>().ToList();
}
我深入研究了源代码并找到了解决方案。
如果您检查 Int32Converter 的来源,您可能会看到,它使用成员中定义的 NumberStyles 作为属性进行转换,或者获取整数的默认值。
当我将 NumberStyles 属性设置为 Number 时,它无需任何其他更改即可正常工作。我更喜欢这个解决方案,因为我不必更改 属性.
的预期类型所以我只需要将 class 定义更改为:
public class TestClass
{
[Name("MyValue"), CsvHelper.Configuration.Attributes.Optional, NumberStyles(NumberStyles.Number)]
public int MyValue { get; set; }
}