【问题标题】:Trim value before reading读取前修剪值
【发布时间】:2021-03-15 10:28:06
【问题描述】:

我有一个 csv,我需要在一个列中读取它包含一个整数值,但值后面有一个空格,所以在 csv 中,值是"1,264 "

在我的班级里

public int MyValue { get; set; }

但是当我尝试读取记录时,我收到以下错误:

TypeConverterException:无法执行转换。 文本:'1,264' 成员类型:System.Int32 TypeConverter:'CsvHelper.TypeConversion.Int32Converter' IReader 状态:ColumnCount:0 CurrentIndex:26 HeaderRecord:

显然我需要修剪该字段中的空白区域。我无法控制初始格式的格式。

我可以使它成为一个字符串属性并在第二遍解析它,但我想看看是否有其他方法。

更新

我尝试删除空格,但仍然出现错误。我原以为这可能是文化信息问题,当我阅读时,我有以下代码:

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

考虑一个包含单列单行标题的文件(除了标题):

MyValue 
"1,264 "

更新 3

我当前的语言环境规定逗号是小数分隔符,点是千位分隔符。

【问题讨论】:

  • 您确定不是因为文本使用逗号作为小数点,而是您在需要点作为小数点的语言环境中解析它?
  • 如果您手动删除空间,您是否仍然收到错误?你确定问题不是那个逗号吗?
  • 您说的都对,手动删除逗号并不能修复错误。我在问题中添加了更多信息。
  • 你可以试试 TrimOptions = TrimOptions.InsideQuotes 吗?
  • 越来越近,TrimOptions.InsideQuotes 修剪了值,但它仍然无法解析它。我正在添加一些示例。

标签: c# csvhelper


【解决方案1】:

我研究了源代码并找到了解决方案。

如果您查看Int32Converter 的来源,您可能会看到,它使用成员中定义的 NumberStyles 作为属性进行转换或获取默认整数。

当我将 NumberStyles 属性设置为 Number 时,它无需任何其他更改即可工作。我更喜欢这种解决方案,因为我不必更改属性的预期类型。

所以我只需要将类定义更改为:

public class TestClass
{
    [Name("MyValue"), CsvHelper.Configuration.Attributes.Optional, NumberStyles(NumberStyles.Number)]
    public int MyValue { get; set; }
}

【讨论】:

  • 这是正确的。您还可以指定将 CultureInfo 设置为 CultureInfo.InvariantCulture
  • 我认为这比当前接受的答案或我自己的答案要好很多。
  • 我不能接受我自己的答案 2 天 :)
【解决方案2】:

所以,正如 cmets 中已经提到的那样,1.264double,并且尝试将其解析为整数将引发异常。在默认的 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; }
}

【讨论】:

  • 我的数字用逗号表示千位分隔符。
  • 我直接尝试了您的代码,但是当我将 Value 设置为 int 类型时它可以工作,然后当我使用 ,. 时出现相同的错误。
  • 好吧,我接受你的回答,因为它确实显示了如何处理我的问题。我确实有一个问题,关心具有千位分隔符的数字以确定它是否能够转换为 int 是正确的,但这是一个不同的问题
【解决方案3】:

我能够在不使用 TypeConverter 将 int 声明更改为 double 的情况下解决问题

步骤如下:

首先创建类型转换器类

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-05
    • 1970-01-01
    • 1970-01-01
    • 2015-05-13
    • 1970-01-01
    • 2014-03-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多