【问题标题】:CsvHelper not parsing correctlyCsvHelper 未正确解析
【发布时间】:2016-04-06 18:59:45
【问题描述】:

我有以下 CSV。

Org Defined ID,Username,FirstName,LastName,Attempt #,Attempt Start,Attempt End,Section #,Q #,Q Type,Q Title,Q Text,Bonus?,Difficulty,Answer,Answer Match,Score,Out Of
,testomalley,Test,O'Malley,1,2/3/2016 15:24,2/3/2016 15:28,,1,LA,Q(1) 1- 5 Part 1,"Scenario 1 for Questions 1 through 5. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.  Part 1 - Sed ut perspiciatis unde omnis iste natus error sit voluptatem.",FALSE,1,Here is my answer o grader. Isn't it brilliant?,,0,2

现在这是我正在尝试将其转换为的对象:

public class Exam
{
    public int? OD_ID { get; set; }
    public string Username { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int AttemptNo { get; set; }
    public DateTime AttemptStart { get; set; }
    public DateTime AttemptEnd { get; set; }
    public int? SectionNo { get; set; }
    public int QuestionNo { get; set; }
    public string QuestionType { get; set; }
    public string QuestionTitle { get; set; }
    public string Questiontext { get; set; }
    public string Bonus { get; set; }
    public int Difficulty { get; set; }
    public string Answer { get; set; }
    public string AnswerMatch { get; set; }
    public int Score { get; set; }
    public int OutOf { get; set; }
}

我已经定义了这张地图:

public sealed class ExamMap : CsvHelper.Configuration.CsvClassMap<Exam>
{
    public ExamMap()
    {
        Map(m => m.OD_ID).Name("Org Defined ID");
        Map(m => m.Username).Name("Username");
        Map(m => m.FirstName).Name("FirstName");
        Map(m => m.LastName).Name("LastName");
        Map(m => m.AttemptNo).Name("Attempt #");
        Map(m => m.AttemptStart).Name("Attempt Start");
        Map(m => m.AttemptEnd).Name("Attempt End");
        Map(m => m.SectionNo).Name("Section #");
        Map(m => m.QuestionNo).Name("Q #");
        Map(m => m.QuestionType).Name("Q Type");
        Map(m => m.QuestionTitle).Name("Q Title");
        Map(m => m.Questiontext).Name("Q Text");
        Map(m => m.Bonus).Name("Bonus?").TypeConverterOption(true, "TRUE").TypeConverterOption(false, "FALSE");
        Map(m => m.Difficulty).Name("Difficulty");
        Map(m => m.Answer).Name("Answer");
        Map(m => m.AnswerMatch).Name("Answer Match");
        Map(m => m.Score).Name("Score");
        Map(m => m.OutOf).Name("Out Of");
    }
}

我的 DateTime 字段的这个 TypeConversion 选项:

var options = new CsvHelper.TypeConversion.TypeConverterOptions
{
    //        2/3/2016 15:24
    Format = "MM/dd/yyyy HH:nn", // also tried "g" with no success.
};

这是解析 CSV 文件的代码:

using (StreamReader sr = new StreamReader(fileName))
{
    using (CsvReader csvread = new CsvReader(sr))
    {
        csvread.Configuration.WillThrowOnMissingField = false;
        csvread.Configuration.HasHeaderRecord = true;
        CsvHelper.TypeConversion.TypeConverterOptionsFactory.AddOptions<DateTime>(options);

        List<Exam> Exams = csvread.GetRecords<Exam>().ToList();
        foreach (var rec in Exams) 
        {
          // Each record will be fetched and printed on the screen
          // checking values of rec here...
        }
    }
}

以下是它的解析方式:

为什么它没有正确解析 DateTime 字段以及为什么没有填充这些属性?

问号
问题类型
问题标题
问题文本
答案匹配
尝试否
没有

【问题讨论】:

  • 您的日期时间格式为 MM/dd/yyyy HH:nn。应该是“MM/dd/yyyy HH:mm,带 mm,而不是 nn。
  • 这并没有改变结果。即使将其更改为“M/d/yyyy HH:mm”也不起作用。

标签: c# csv csvhelper


【解决方案1】:

您可以像这样添加一个用于 DateTime 解析的方法(您甚至可以现在设置断点并修改选项):

Map(t => t.AttemptStart).Name("Attempt Start")
    .ConvertUsing(new Func<CsvHelper.ICsvReaderRow, DateTime>(r =>
        {
            DateTime dateTimeValue;
            if (DateTime.TryParse(r["Attempt Start"], null,
                System.Globalization.DateTimeStyles.AllowWhiteSpaces, out dateTimeValue))
            {
                return dateTimeValue;
            }

            return default(DateTime);
        }));

缺少的字段可能是基于 DateTime 解析问题的错误。乍一看是对的。

【讨论】:

  • 您的变量表明您应该使用 TryParseExact。
  • 也试过了,结果相同:DateTime.TryParse(r["Attempt Start"], out dateTimeValue)。事实上,添加 ConvertUsing 导致值设置为 null 在它们设置为 1/1/0001 12:00:00 AM 之前我将 dateTimeValue 定义更改为此,所以我不会得到空值:DateTime dateTimeValue = DateTime.Now;return dateTimeValue
  • 你是对的,我修复了我的代码以根据您的示例成功解析 DateTime(请参阅dotnetfiddle.net/Na4CPM)。奇怪的是它甚至没有达到你的断点。您能否.Ignore() 一些属性并检查第一个导致问题的属性?
  • 仍然永远不会在断点处停止。我什至不确定它是否正在使用地图,因为我将.Ignore 添加到除了Attempt Start 之外的所有其他属性中,并且在填充许多其他属性时得到了相同的结果。是否有一种特殊的方式告诉它使用地图类,我在文档中没有看到它?
  • 我在文档中看到了这一点,但不确定它的含义:“您需要在配置中注册您的类映射”
【解决方案2】:

对我来说一切似乎都很好。我所做的就是这个。

csv.Configuration.RegisterClassMap<ExamMap>();
csv.GetRecords<Exam>().ToList().Dump();

我也可以很好地显示您缺少的所有字段。

默认情况下,CsvHelper 将解析所有这些类型。如果需要,您还可以更轻松地添加类型转换器选项。

TypeConverterOptions

这是来自 linqpad 的完整示例。

void Main()
{
    using (var stream = new MemoryStream())
    using (var reader = new StreamReader(stream))
    using (var writer = new StreamWriter(stream))
    using (var csv = new CsvReader(reader))
    {
        writer.WriteLine("Org Defined ID,Username,FirstName,LastName,Attempt #,Attempt Start,Attempt End,Section #,Q #,Q Type,Q Title,Q Text,Bonus?,Difficulty,Answer,Answer Match,Score,Out Of");
        writer.WriteLine(", testomalley, Test, O'Malley,1,2/3/2016 15:24,2/3/2016 15:28,,1,LA,Q(1) 1- 5 Part 1,\"Scenario 1 for Questions 1 through 5. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.  Part 1 - Sed ut perspiciatis unde omnis iste natus error sit voluptatem.\",FALSE,1,Here is my answer o grader. Isn't it brilliant ?,, 0, 2");
        writer.Flush();
        stream.Position = 0;

        csv.Configuration.RegisterClassMap<ExamMap>();
        csv.GetRecords<Exam>().ToList().Dump();
    }
}

public class Exam
{
    public int? OD_ID { get; set; }
    public string Username { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int AttemptNo { get; set; }
    public DateTime AttemptStart { get; set; }
    public DateTime AttemptEnd { get; set; }
    public int? SectionNo { get; set; }
    public int QuestionNo { get; set; }
    public string QuestionType { get; set; }
    public string QuestionTitle { get; set; }
    public string Questiontext { get; set; }
    public string Bonus { get; set; }
    public int Difficulty { get; set; }
    public string Answer { get; set; }
    public string AnswerMatch { get; set; }
    public int Score { get; set; }
    public int OutOf { get; set; }
}

public sealed class ExamMap : CsvHelper.Configuration.CsvClassMap<Exam>
{
    public ExamMap()
    {
        Map(m => m.OD_ID).Name("Org Defined ID");
        Map(m => m.Username).Name("Username");
        Map(m => m.FirstName).Name("FirstName");
        Map(m => m.LastName).Name("LastName");
        Map(m => m.AttemptNo).Name("Attempt #");
        Map(m => m.AttemptStart).Name("Attempt Start");
        Map(m => m.AttemptEnd).Name("Attempt End");
        Map(m => m.SectionNo).Name("Section #");
        Map(m => m.QuestionNo).Name("Q #");
        Map(m => m.QuestionType).Name("Q Type");
        Map(m => m.QuestionTitle).Name("Q Title");
        Map(m => m.Questiontext).Name("Q Text");
        Map(m => m.Bonus).Name("Bonus?").TypeConverterOption(true, "TRUE").TypeConverterOption(false, "FALSE");
        Map(m => m.Difficulty).Name("Difficulty");
        Map(m => m.Answer).Name("Answer");
        Map(m => m.AnswerMatch).Name("Answer Match");
        Map(m => m.Score).Name("Score");
        Map(m => m.OutOf).Name("Out Of");
    }
}

【讨论】:

  • Josh,显然你没有阅读我对@Scoregraphic 帖子的最后评论。我确实解决了这个问题,并在 GitHub 上发布了更新您的文档的请求。
猜你喜欢
  • 1970-01-01
  • 2012-01-28
  • 1970-01-01
  • 2016-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-01
  • 2016-11-25
相关资源
最近更新 更多