自定义分隔符在 CsvHelper 中不起作用

如何解决自定义分隔符在 CsvHelper 中不起作用

我正在使用 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

解决方法

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

  • Delimiter。用于在单个 CSV 行中分隔字段的字符。 (通常为 ,,此处为 ~)。

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

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

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

上面前三个字符设置的功能在CsvMode enum的注释中说明:

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?