CsvHelper 类型转换,带字符串和整数的列到整数

Posted

技术标签:

【中文标题】CsvHelper 类型转换,带字符串和整数的列到整数【英文标题】:CsvHelper type conversion, column with string and ints to int 【发布时间】:2021-11-03 03:50:07 【问题描述】:

我有一个人为的 csv 文件

  "Id","Name"
  "10","Foo"
  "Team1Id","Joe"
  "Team1Id","Blogs"
  "Team2Id","Foo Bar"

public class MyClass

    public int Id  get; set; 
    public string Name  get; set; 

public class MyClassMap : CsvHelper.Configuration.ClassMap<MyClass>

    public MyClassMap()
    
        Map(m => m.Id).Name("Id").???Convert???
        Map(m => m.Name).Name("Name");
    

我想将 Id 列映射到一个 int,所以我想我想自定义转换“Team1Id”和“Team2Id”到一些相关的固定值(“Team1Id”=> -1,“Team2Id”=> - 2)

【问题讨论】:

根据文档,您可以滚动自己的 TypeConverter ,例如:joshclose.github.io/CsvHelper/examples/configuration/class-maps/… 您是否要剥离非 nUmbers 并使结果为负数的关系,因此 Team278Id 将是 -278? @CaiusJard 我在想,如果字典中有 100,000 个键,您必须全部阅读它们才能确定下一个值。但是有办法解决这个问题,所以我删除了评论。 @stuartd 啊,有道理.. 是的,我想我会保持配对号码nextId,如果我正在制作一个新的字典条目,我会d[somelkey] = nextId--;,所以我不必 Min() 字典值 谢谢@david,辛苦了。 lidqy TypeConverter 示例覆盖了 ConvertFromString / ConvertToString,我看不出这有什么帮助。 stuart / caius 我在列中只有几个文本项,它们实际上并不包含数字,而是巧妙的解决方案。谢谢大家 【参考方案1】:

这是否符合您的要求?

void Main()

    var mappings = new Dictionary<string, int>   "Team1Id", -1 , "Team2Id", -2 ;
    
    using (var reader = new StringReader("Id,Name\n10,Foo\nTeam1Id,Joe\nTeam1Id,Blogs\nTeam2Id,Foo Bar"))
    using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
    
        csv.Context.RegisterClassMap(new MyClassMap(mappings));
        var records = csv.GetRecords<MyClass>().ToList();
       


public class MyClassMap : ClassMap<MyClass>

    public MyClassMap(IDictionary<string,int> mappings)
    
        Map(x => x.Id).Convert(args =>
        
            var idValue = args.Row.GetField("Id");
            
            if (mappings.ContainsKey(idValue))
            
                return mappings[idValue];
             else
            
                int.TryParse(idValue, out int value);
                
                return value;
            
            
        );
        Map(x => x.Name);
    


public class MyClass

    public int Id  get; set; 
    public string Name  get; set; 

【讨论】:

【参考方案2】:

这是对 D.Specht 答案的修改,以纳入 stuartd 的评论

void Main()

    using var reader = new StringReader("Id,Name\n10,Foo\nTeam1Id,Joe\nTeam1Id,Blogs\nTeam2Id,Foo Bar");
    using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);
    csv.Context.RegisterClassMap(new MyClassMap(mappings));
    var records = csv.GetRecords<MyClass>().ToList();


public class MyClassMap : ClassMap<MyClass>

    private _mappings = new Dictionary<string, int>();
    private _nextId = -1;

    public MyClassMap(IDictionary<string,int> mappings)
    
        Map(x => x.Id).Convert(args =>
        
            var idValue = args.Row.GetField("Id");
            
            if(int.TryParse(idValue, out int value))
                return value;
           
            if (_mappings.TryGetValue(idValue, out int value))
                return value;
            else
                return (mappings[idValue] = nextId--);
            
        );
        Map(x => x.Name);
    


public class MyClass

    public int Id  get; set; 
    public string Name  get; set; 

如果你只是想去掉文本只留下数字,那么 team1234xyz 变成 -1234 和 123abc456 变成 -123456:

void Main()

    using var reader = new StringReader("Id,Name\n10,Foo\nTeam1Id,Joe\nTeam1Id,Blogs\nTeam2Id,Foo Bar");
    using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);
    csv.Context.RegisterClassMap(new MyClassMap(mappings));
    var records = csv.GetRecords<MyClass>().ToList();


public class MyClassMap : ClassMap<MyClass>

    public MyClassMap(IDictionary<string,int> mappings)
    
        Map(x => x.Id).Convert(args =>
        
            var idValue = args.Row.GetField("Id");
            
            if(int.TryParse(idValue, out int value))
                return value;
            else
                return -Convert.ToInt32(new string(value.Where(c => Char.IsDigit(c))));
            
        );
        Map(x => x.Name);
    


public class MyClass

    public int Id  get; set; 
    public string Name  get; set; 

【讨论】:

以上是关于CsvHelper 类型转换,带字符串和整数的列到整数的主要内容,如果未能解决你的问题,请参考以下文章

将 CsvHelper 自定义转换器应用于一组类的所有字符串属性

将包含字符串和 NAN 的列转换为 Pandas 中的整数列表

oracle中的列到行

具有不同日期的列到行

Excel 列到 SQL 语句

Golang✔️走进 Go 语言✔️ 第五课 类型转换