【问题标题】:Properly escape a double quote in CSV正确转义 CSV 中的双引号
【发布时间】:2013-07-22 10:10:14
【问题描述】:

我的 CSV 中有这样一行:

"Samsung U600 24"","10000003409","1","10000003427"

24 旁边的引号用于表示英寸,而该引号旁边的引号将关闭该字段。我正在阅读带有fgetcsv 的行,但解析器出错并将值读取为:

Samsung U600 24",10000003409"

我尝试在英寸引号前加一个反斜杠,但后来我在名称中得到一个反斜杠:

Samsung U600 24\"

有没有办法在 CSV 中正确转义这个值,以便该值是 Samsung U600 24" ,还是我必须在处理器中对其进行正则表达式?

【问题讨论】:

  • 报价翻倍。就是这样

标签: csv escaping


【解决方案1】:

使用 2 个引号:

"Samsung U600 24"""

【讨论】:

  • RFC-4180,段落“如果使用双引号括住字段,则出现在字段中的双引号必须通过在其前面加上另一个双引号来进行转义。”
  • 正如 tommed 所说,您只需添加一个双引号即可转义双引号。您可以使用名为 csvfix 的命令行工具来检测任何不符合的行: csvfix check -nl -v [filename]
  • @SamCritchley 我在这里只看到一个双引号被用来转义。通过“使用 2 个引号”,user4035 表示应将 1 个引号替换为 2 个引号。通过用双引号转义双引号,您可以有效地创建双引号对(2 个双引号)。您最后看到的最后一句话是终止该字段。
  • 非常好的方法。但这需要我在解析之前修改 CSV 文件。
  • @GarfieldCat 试试这个:"world,"",hello"
【解决方案2】:

不仅需要双引号,还需要单引号 (')、双引号 (")、反斜杠 (\) 和 NUL(NULL 字节)。

使用fputcsv() 写,fgetcsv() 读,这将照顾所有。

【讨论】:

  • This comment on the documentation page of fputcsv() 展示了当您想以 csv 格式而不是实际文件输出到浏览器时如何使用 fputcsv()
  • @Angelin Nadar,您能否在声明中添加有关需要双引号、反斜杠和 NUL 的来源?我在RFC-4180 没有找到它。
  • 您实际上不需要转义单引号等。正确的 CSV 文件甚至不需要在仅包含单引号的字段周围添加双引号。如果正确实现了 CSV 阅读器,即使使用这些符号,它也应该正确读取文件。
  • 为什么这个答案被投票?关于转义字符的评论从未得到支持,原始问题也没有询问 PHP。当诸如 Open Office 之类的程序允许您更改字符串分隔符时,这似乎仅适用于字符串分隔符(并且仅适用于所选分隔符)。
  • 如果您真的阅读过 RFC4180 指出CSV 格式有各种[其他] 规范和实现 并列出至少4。 OP 没有指定哪种特定格式,所以我觉得根据对特定文档的假设来否决这个答案是不公平的。
【解决方案3】:

我是用 Java 写的。

public class CSVUtil {
    public static String addQuote(
            String pValue) {
        if (pValue == null) {
            return null;
        } else {
            if (pValue.contains("\"")) {
                pValue = pValue.replace("\"", "\"\"");
            }
            if (pValue.contains(",")
                    || pValue.contains("\n")
                    || pValue.contains("'")
                    || pValue.contains("\\")
                    || pValue.contains("\"")) {
                return "\"" + pValue + "\"";
            }
        }
        return pValue;
    }

    public static void main(String[] args) {
        System.out.println("ab\nc" + "|||" + CSVUtil.addQuote("ab\nc"));
        System.out.println("a,bc" + "|||" + CSVUtil.addQuote("a,bc"));
        System.out.println("a,\"bc" + "|||" + CSVUtil.addQuote("a,\"bc"));
        System.out.println("a,\"\"bc" + "|||" + CSVUtil.addQuote("a,\"\"bc"));
        System.out.println("\"a,\"\"bc\"" + "|||" + CSVUtil.addQuote("\"a,\"\"bc\""));
        System.out.println("\"a,\"\"bc" + "|||" + CSVUtil.addQuote("\"a,\"\"bc"));
        System.out.println("a,\"\"bc\"" + "|||" + CSVUtil.addQuote("a,\"\"bc\""));
    }
}

【讨论】:

  • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
【解决方案4】:

如果值包含逗号、换行符或双引号,则字符串必须用双引号括起来。例如:“此字段中的换行符 \n”。

您可以使用下面的在线工具来转义 "" 和 , 运算符。 https://www.freeformatter.com/csv-escape.html#ad-output

【讨论】:

    【解决方案5】:

    我知道这是一篇旧帖子,但这是我使用扩展方法在 C# 中解决它的方法(以及将空值转换为空字符串)。

    使用以下内容创建一个静态类:

        /// <summary>
        /// Wraps value in quotes if necessary and converts nulls to empty string
        /// </summary>
        /// <param name="value"></param>
        /// <returns>String ready for use in CSV output</returns>
        public static string Q(this string value)
        {
            if (value == null)
            {
                return string.Empty;
            }
            if (value.Contains(",") || (value.Contains("\"") || value.Contains("'") || value.Contains("\\"))
            {
                return "\"" + value + "\"";
            }
            return value;
        }
    

    然后对于您要写入 CSV 的每个字符串,而不是:

    stringBuilder.Append( WhateverVariable );
    

    你只要这样做:

    stringBuilder.Append( WhateverVariable.Q() );
    

    【讨论】:

    • 这不会错过嵌入引号的加倍吗?
    猜你喜欢
    • 1970-01-01
    • 2018-01-21
    • 1970-01-01
    • 1970-01-01
    • 2020-02-21
    • 1970-01-01
    • 2020-11-26
    • 1970-01-01
    • 2013-05-10
    相关资源
    最近更新 更多