【问题标题】:Custom delimiter doesn't work in CsvHelper自定义分隔符在 CsvHelper 中不起作用
【发布时间】:2021-03-26 21:51:09
【问题描述】:

我正在使用 CsvHelper v26.1.0 读取以下由~分隔的文本文件:

123~John
234~Joe "Public"

但是文件中的双引号导致 CsvHelper 将它们视为错误数据。我通过删除双引号对其进行了测试,并且效果很好。但问题是,我已经设置了自定义分隔符,为什么双引号仍然会导致问题?

public class AccountDtoMap : ClassMap<AccountDto>
{
    public AccountDtoMap()
    {
        Map(m => m.Number).Index(0);
        Map(m => m.Name).Index(1);
    }
}

var cfg = new CsvHelper.Configuration.CsvConfiguration(CultureInfo.InvariantCulture)
{
    Delimiter = "~",
    HasHeaderRecord = false,
    MissingFieldFound = (context) => { errs.Add($"{typeof(T)} missing field: {context.Context.Parser.RawRecord}"); },
    BadDataFound = (context) => { errs.Add($"{typeof(T)} bad data: {context.RawRecord}"); },
};

using (var csv = new CsvReader(new StreamReader(file), cfg))
{
    csv.Context.RegisterClassMap<AccountDtoMap>();
    return csv.GetRecords<T>().ToList();
}

可运行的演示 here.

【问题讨论】:

  • 双引号是 CsvHelper 用来引用(封装)字段的字符。尝试将双引号加倍(例如""Public""),或更改引号字符
  • @greenjaed 尝试将引号加倍,但仍然出现同样的错误。
  • 抱歉,我的建议不完整。尝试引用整个字段,然后将双引号加倍。
  • 您可能会将分隔符与Escape 和/或Quote 设置混淆。如果您的单元格包含嵌入的转义字符,您可能需要按照RFC 4180 2.7 转义整个单元格
  • @dbc 将 Escape 和 Quote 字符都更改为 \t 后,它起作用了。我很确定源文件不会有标签。

标签: c# csv csvhelper


【解决方案1】:

要解析问题中显示的 CSV(版本 26.1.0),您需要正确配置以下所有 CsvConfiguration 设置,而不仅仅是分隔符:

  • Delimiter。用于在单个 CSV 行中分隔字段的字符。 (通常是,,这里是~)。

  • Escape,默认"。用于其他需要转义的字符之前的字符。

  • Quote,默认"。根据RFC4180,用于包装需要在开头和结尾加上引号的字段的字符。

  • Mode。解析和写入时使用的CsvMode

上面前三个字符设置的作用在CsvMode enum的cmet中都有说明:

public enum CsvMode
{
    /// Uses RFC 4180 format (default).
    /// If a field contains a CsvConfiguration.Delimiter or CsvConfiguration.NewLine,
    /// it is wrapped in CsvConfiguration.Quote's.
    /// If quoted field contains a CsvConfiguration.Quote, it is preceded by CsvConfiguration.Escape.
    RFC4180 = 0,

    /// Uses escapes.
    /// If a field contains a CsvConfiguration.Delimiter, CsvConfiguration.NewLine,
    /// or CsvConfiguration.Escape, it is preceded by CsvConfiguration.Escape.
    /// Newline defaults to \n.
    Escape,

    /// <summary>
    /// Doesn't use quotes or escapes.
    /// This will ignore quoting and escape characters. This means a field cannot contain a
    /// CsvConfiguration.Delimiter, CsvConfiguration.Quote, or
    /// CsvConfiguration.NewLine, as they cannot be escaped.
    NoEscape
}

Joe "Public" 字段包含嵌入的转义字符,这些字符本身没有转义,这导致 CshHelper 报告错误。为了避免该错误,您有几种可能的选择,包括:

  1. 设置CsvMode.NoEscape 完全禁用转义和引用:

    var cfg = new CsvHelper.Configuration.CsvConfiguration(CultureInfo.InvariantCulture)
    {
        Mode = CsvMode.NoEscape,
        // Remainder unchanged.
    

    当然,如果您这样做,您的 CSV 文件不能在字段中包含分隔符或换行符。

    演示小提琴 #1 here.

  2. 设置Mode = CsvMode.Escape 以禁用引号中的字段换行,并将Escape 设置为其他一些您不希望在实际文件中遇到的字符,例如\\t

    var cfg = new CsvHelper.Configuration.CsvConfiguration(CultureInfo.InvariantCulture)
    {
        Mode = CsvMode.Escape,
        Escape = '\\',
        // Remainder unchanged.
    

    即使您这样做了,CSV 字段中的分隔符、转义符和换行符仍必须使用选定的转义符正确转义。

    演示小提琴#2 here.

  3. 设置Mode = CsvMode.Escape 并修复您的文件以正确转义转义字符:

    234~Joe ""Public""
    

    演示小提琴#3 here.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多