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