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 自定义转换器应用于一组类的所有字符串属性