【问题标题】:Parsing a CSV: Edge Cases解析 CSV:边缘案例
【发布时间】:2012-03-31 15:24:10
【问题描述】:

免责声明:我实际上并不是在解析 CSV,而是在解析类似 CSV 的格式;我对使用预建库不感兴趣。

解析以下两行的正确方法是什么?:

a,b"c"d,e
a,"bc"d,e

即,(a) 值中间有引号,(b) 开头有引号,但在下一个值之前没有结束引号。

我不知道应该如何处理这些情况(这将是最直观的)。


我的想法是(a)应该被解析为a,b"c"d,e(引号留在里面),并且(b)应该以同样的方式解析,a,"bc"de。但是,让我介绍第三种情况,a,"b,c"d,e——我们是否在“b”和“c”之间分割第二个逗号?

【问题讨论】:

  • 最终,这取决于您在分隔符之间允许的确切内容 - 以及您希望如何解释它。没有合适的方法,你必须定义规则。
  • @moodywoody:那么,其他解析器如何处理这些情况?作为用户,如果您输入逗号分隔的标签列表(类似于 SO 的标签,但带有逗号分隔符),您会期待什么行为?
  • 就我个人而言,当涉及到引文之类的东西时,我什么都不期待 - 我要求一个定义(我知道这有点逃避,但我喜欢我的问题是“定义明确”)。无论如何,您可能会发现这两个处理 perl 和 csv 文件的链接很有趣stackoverflow.com/questions/633607/…en8848.com.cn/Reilly%20Books/perl3/cookbook/ch01_16.htm.
  • "([^\"\\]*(?:\\.[^\"\\]*)*)" -- 这是一个非常漂亮的正则表达式。我不认为你可以用正则表达式解析字符串并正确地进行转义(必须确保有一个奇数);我之前问过也没用。我将不得不更深入地研究它。我从未使用过 perl,但我想我明白了。
  • 如果我正确阅读了 Perl 解决方案,"bc"d 将被完全省略,因为结束引号后没有逗号。我想我有点喜欢......它的格式不正确,所以它没有被包括在内,但整个 CSV 并没有爆炸。 i.imgur.com/RFWoq.png

标签: parsing csv dataformat


【解决方案1】:

这是我的方法 (C#) 将 csv 吐出到 html 表的一部分 - 它具有这样的逗号解析:

string[] cells = line.Split(','); // empty cells needed as well
bool noComma = true;

for (int i = 0; i < cells.Length; i++)
{
    string cellI = cells[i];
    int numberOfDoubleQuote = cellI.Count(f => f == '"');
    // == 0 means comma in between quotes
    if (numberOfDoubleQuote == 1)
    {
        noComma = !noComma;
        if (!noComma)
            sLine += "<td>" + cellI;
        else
            sLine += "," + cellI + "</td>";
    }
    else
    {
        if (noComma)
            sLine += "<td>" + cellI + "</td>";
        else
            sLine += "," + cellI;
    }
}

【讨论】:

  • 因此,您基本上拆分了所有逗号,然后如果它们包含单引号,则“加入”单元格......但我认为您没有很好地涵盖这些案例。例如,它将如何处理 a,b",c ?如果我没看错,它会输出 a,b",c 这似乎是错误的。
【解决方案2】:

如果您想与 Excel 保持一致,您将如何解析它:

输入:

a,b"c"d,e
a,"bc"d,e
a,"b,c"d,e

已解析(以 JSON 格式):

[
  ["a", "b\"c\"d", "e"],
  ["a", "bcd", "e"],
  ["a","b,cd", "e"]
]

解析逻辑是:

  • 如果该行的第一个字符或紧跟在逗号之后的字符是 dbl-quote,则:
    • 将其后的所有内容视为“引用”,直到到达结束引号(当然,将两个引号视为转义的 dbl-quote)。从单元格值中删除开头和结尾的引号
    • 在到达“结束引号”之后,将单元格值中结束引号之后的任何内容作为文字值包含在内,直到到达逗号或换行符
  • 否则,将逗号后面的所有内容视为文字值,直到到达逗号或换行符

请注意,这意味着如果您在单元格分隔逗号后有一个空格,后跟一个 dbl-quote,则会得到不同的结果,如果您在逗号后没有空格(后跟一个 dbl-quote)

【讨论】:

    猜你喜欢
    • 2010-10-28
    • 1970-01-01
    • 1970-01-01
    • 2016-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-18
    • 2018-04-15
    相关资源
    最近更新 更多