C# 使用特定的列分隔符解析csv文件&;使用CsvHelper库的字符串存储模块

C# 使用特定的列分隔符解析csv文件&;使用CsvHelper库的字符串存储模块,c#,csv,C#,Csv,我在.NETC#项目中使用这个很棒的库来满足CSV解析需求 如果我有一个如下所示的CSV文件: SupplierSku,MappedSageSku EG1234,EGCD1234 EG4567,EG-XZ567 public class SkuMapping { public string SupplierSku { get; set; } public string MappedSageSku { get; set; } } // Open & parse sele

我在.NETC#项目中使用这个很棒的库来满足CSV解析需求

如果我有一个如下所示的CSV文件:

SupplierSku,MappedSageSku
EG1234,EGCD1234
EG4567,EG-XZ567
public class SkuMapping
{
    public string SupplierSku { get; set; }
    public string MappedSageSku { get; set; }
}
// Open & parse selected csv file
var csvReader = new CsvReader(File.OpenText(selectSkuMapping.Text));
var skuMappings = csvReader.GetRecords<SkuMapping>();

// Do something with each row
foreach (SkuMapping skuMapping in skuMappings)
{
    // ...
}
我通常创建一个DTO类,如下所示:

SupplierSku,MappedSageSku
EG1234,EGCD1234
EG4567,EG-XZ567
public class SkuMapping
{
    public string SupplierSku { get; set; }
    public string MappedSageSku { get; set; }
}
// Open & parse selected csv file
var csvReader = new CsvReader(File.OpenText(selectSkuMapping.Text));
var skuMappings = csvReader.GetRecords<SkuMapping>();

// Do something with each row
foreach (SkuMapping skuMapping in skuMappings)
{
    // ...
}
并按如下方式解析csv文件:

SupplierSku,MappedSageSku
EG1234,EGCD1234
EG4567,EG-XZ567
public class SkuMapping
{
    public string SupplierSku { get; set; }
    public string MappedSageSku { get; set; }
}
// Open & parse selected csv file
var csvReader = new CsvReader(File.OpenText(selectSkuMapping.Text));
var skuMappings = csvReader.GetRecords<SkuMapping>();

// Do something with each row
foreach (SkuMapping skuMapping in skuMappings)
{
    // ...
}
在哪里<代码>列分隔符=
字符串附件
=

我需要的数据:列索引
0
(PartNumb)和列索引
1
(InStock)

示例2 其中;
列分隔符
=
|
字符串附件
=
%

我需要的数据:列索引
0
(供应商SKU)和列索引
2
(库存状态)



鉴于上述情况,使用
CsvHelper
库解析任意csv文件的最佳方法是什么(其中
列分隔符
字符串附件
列索引
已知)?我还需要跳过csv上的第一行的选项(有时csv包含标题行,有时不包含标题行).

使用CsvHelper,这似乎有效:

var textToParse = @"SupplierSku,CatIds,StockStatus,Active
%ADA-BB-124%|4,5,1|%AV%|1
%XAS-E4-S11%|97,41,65|%OS%|0";

string supplierSku;
string stockStatus;

using (var stringReader = new StringReader(textToParse))
{
    using (var reader = new CsvReader(stringReader))
    {
        reader.Configuration.Delimiter = ",";
        reader.Configuration.HasHeaderRecord = true; // If there is no header, set to false.

        while (reader.Read())
        {
            supplierSku = reader.GetField("SupplierSku"); // Or reader.GetField(0)
            stockStatus = reader.GetField("StockStatus"); // Or reader.GetField(2)

            Console.WriteLine($"SKU: {supplierSku}; Status: {stockStatus}");
        }
    }
}

但是,它不会自动修剪/删除引号字符-您可以使用
trim()
Substring()
轻松地进行修剪/删除。需要更多的手动操作,但仍然比手动操作简单。

使用CsvHelper,这似乎很有效:

var textToParse = @"SupplierSku,CatIds,StockStatus,Active
%ADA-BB-124%|4,5,1|%AV%|1
%XAS-E4-S11%|97,41,65|%OS%|0";

string supplierSku;
string stockStatus;

using (var stringReader = new StringReader(textToParse))
{
    using (var reader = new CsvReader(stringReader))
    {
        reader.Configuration.Delimiter = ",";
        reader.Configuration.HasHeaderRecord = true; // If there is no header, set to false.

        while (reader.Read())
        {
            supplierSku = reader.GetField("SupplierSku"); // Or reader.GetField(0)
            stockStatus = reader.GetField("StockStatus"); // Or reader.GetField(2)

            Console.WriteLine($"SKU: {supplierSku}; Status: {stockStatus}");
        }
    }
}

但是,它不会自动修剪/删除引号字符-您可以使用
trim()
Substring()
轻松地修剪/删除引号字符。手动操作要多一些,但仍然比手动操作简单。

答案取决于您想要什么:

  • 在开始解析之前,您知道允许使用哪些分隔符吗
如果您不知道允许使用哪些分隔符,您就有麻烦了:“A”是分隔符吗?B”是分隔符吗?让我们假设有一组您认为适合作为要分析的实际CSV流的分隔符的字符

  • 用相同的分隔符替换所有出现的分隔符,例如“;”
  • 您可以使用String.Replace(char,char)为每个接受的分隔符执行此操作,或者使用正则表达式

    • 是否要按名称按列数选择列
  • 如果只需要某些列,请创建一个映射,告诉CsvHelper哪些列必须映射到哪个目的地

    示例:如果需要将列“MyColumn”映射到属性YourProperty,请创建映射:

    private sealed class MyCsvConverterMap : CsvClassMap<MyDestinationType>
    {
        public MyCsvConverterMap()
        {
            Map(item => item.YourProperty).Name("MyColumn");
            // map all properties in your destination to a column
        }
    }
    
    using (TextReader txtReader = new StringReader(...))
    {
        CsvReader csvReader = new CsvReader(txtReader);
        csvReader.Configuration.Delimiter = ";";
        csvReader.Configuration.HasHeaderRecord = true;
        csvReader.Configuration.RegisterClassMap(new MyCsvConverterMap());
    
        while (csvReader.Read())
        {
             MyDestinationType convertedRecord = csvReader.GetRecord<MyDestinationType>();
             ...
    
    私有密封类MyCsvConverterMap:CsvClassMap
    {
    公共MyCsvConverterMap()
    {
    Map(item=>item.YourProperty).Name(“MyColumn”);
    //将目标中的所有属性映射到列
    }
    }
    使用(TextReader txtReader=新的StringReader(…)
    {
    CsvReader CsvReader=新的CsvReader(txtReader);
    csvReader.Configuration.Delimiter=“;”;
    csvReader.Configuration.HasHeaderRecord=true;
    RegisterClassMap(新的MyCsvConverterMap());
    while(csvReader.Read())
    {
    MyDestinationType convertedRecord=csvReader.GetRecord();
    ...
    
    添加

    也可以按列编号映射,而不是按列名映射。请参阅各种映射的说明:
    答案取决于你想要什么:

    • 在开始解析之前,您知道允许使用哪些分隔符吗
    如果您不知道允许使用哪些分隔符,您就有麻烦了:“A”是分隔符吗?B”是分隔符吗?让我们假设有一组您认为适合作为要分析的实际CSV流的分隔符的字符

  • 用相同的分隔符替换所有出现的分隔符,例如“;”
  • 您可以使用String.Replace(char,char)为每个接受的分隔符执行此操作,或者使用正则表达式

    • 是否要按名称按列数选择列
  • 如果只需要某些列,请创建一个映射,告诉CsvHelper哪些列必须映射到哪个目的地

    示例:如果需要将列“MyColumn”映射到属性YourProperty,请创建映射:

    private sealed class MyCsvConverterMap : CsvClassMap<MyDestinationType>
    {
        public MyCsvConverterMap()
        {
            Map(item => item.YourProperty).Name("MyColumn");
            // map all properties in your destination to a column
        }
    }
    
    using (TextReader txtReader = new StringReader(...))
    {
        CsvReader csvReader = new CsvReader(txtReader);
        csvReader.Configuration.Delimiter = ";";
        csvReader.Configuration.HasHeaderRecord = true;
        csvReader.Configuration.RegisterClassMap(new MyCsvConverterMap());
    
        while (csvReader.Read())
        {
             MyDestinationType convertedRecord = csvReader.GetRecord<MyDestinationType>();
             ...
    
    私有密封类MyCsvConverterMap:CsvClassMap
    {
    公共MyCsvConverterMap()
    {
    Map(item=>item.YourProperty).Name(“MyColumn”);
    //将目标中的所有属性映射到列
    }
    }
    使用(TextReader txtReader=新的StringReader(…)
    {
    CsvReader CsvReader=新的CsvReader(txtReader);
    csvReader.Configuration.Delimiter=“;”;
    csvReader.Configuration.HasHeaderRecord=true;
    RegisterClassMap(新的MyCsvConverterMap());
    while(csvReader.Read())
    {
    MyDestinationType convertedRecord=csvReader.GetRecord();
    ...
    
    添加

    也可以按列编号映射,而不是按列名映射。请参阅各种映射的说明:

    您还可以通过
    CsvClassMap
    创建类型安全映射,并从
    DefaultTypeConverter
    类继承以创建CATID的转换器(逗号分隔)

    下面的示例适用于您的示例#2:

    [TestClass]
    公共类CsvHelperTest
    {
    [测试方法]
    公开无效测试()
    {
    var textToParse=“供应商SKU、CATID、库存状态、活动”+Environment.NewLine;
    textToParse+=%ADA-BB-124%| 4,5,1 |%AV%| 1“+Environment.NewLine;
    textToParse+=%XAS-E4-S11%| 97,41,65 |%OS%| 0;
    使用(var stringReader=newstringreader(textToParse))
    {
    使用(变量读取器=新CsvReader(stringReader))
    {
    reader.Configuration.Quote='%';
    reader.Configuration.Delimiter=“|”;
    reader.Configuration.HasHeaderRecord=true;//如果存在n