【问题标题】:Write a string containing commas and double quotes to CSV将包含逗号和双引号的字符串写入 CSV
【发布时间】:2018-03-20 03:52:58
【问题描述】:

我正在尝试在 NetSuite 中生成包含 30,000 多种商品的 Google 购物提要,NetSuite 是一个运行服务器端 JavaScript 的 CRM 系统,它称为 Suitescript 2.0。本质上,它只是带有更多限制的 JavaScript。我的任务是将此产品 Feed 输出为 CSV。

问题是这些项目的产品描述包含可变数量的逗号、双引号、单引号和 HTML。起初,只是逗号引起了我的问题,所以经过一番研究,我将输出的字符串用双引号括起来:

//This function isn't terribly important, but is referenced below

function sanitizeString (desc) {
    var itemDesc;
    if (desc) {
        itemDesc = desc.replace(/(\r\n|\n|\r|\s+|\t| )/gm,' ');
        itemDesc = itemDesc.replace(/,/g, '\,');
        itemDesc = itemDesc.replace(/"/g, '\"');
        itemDesc = itemDesc.replace(/'/g, '\'');
        itemDesc = itemDesc.replace(/ +(?= )/g,'');
    } else {
        itemDesc = '';
    }
    return itemDesc;
}

var row = '';

for (var i = 0; i < columns.length; i++) {
    var col = columns[i];
    row += '"' + sanitizeString(val[col]) + '"';
    if (i != columns.length - 1) {
        row += ',';
    }
}
newFeed.appendLine({value: row});

但是,这些双引号似乎与字符串中的双引号发生了奇怪的交互,从而导致了一些奇怪的格式,即使我的 sanitizeString() 函数应该转义它们。每当描述包含双引号时,下一行都不会得到它自己的行。它被附加到最后一列。

所以,很自然地,我像这样转义了外部引号:

row += '\"' + sanitizeString(val[col]) + '\"';

这样做会让事情变得完全混乱,很多项目不会被推送到新行,而且我会最大限度地增加允许的列数,因为它会继续进行。

另一个自然的解决方案是编辑产品描述,但我并不急于为 30,000 多件商品这样做......

有人知道这里会发生什么吗?我觉得我忽略了一些非常简单的事情......

【问题讨论】:

  • 如果您的转义函数应该在输出中添加反斜杠,您需要转义函数中字符串文字中的反斜杠,即'\\,' 而不是'\,',或者包含'\\\''"\\'" 的单引号。
  • 不,它不应该添加反斜杠。它只是应该为最后的字符串逃脱它们。添加转义的反斜杠会使事情再次变得混乱,并且不会添加新行,而是附加到包含引号的行的末尾...
  • “为最终字符串转义它们”对您意味着什么?这是否意味着最终的字符串将添加反斜杠?例如,如果特定字段的输入是Hello, good bye,那么输出应该是Hello\, good bye,不是吗?对于 CSV,鉴于您要删除换行符并将每个字段放在双引号中,我认为只需要转义双引号 - 尽管由于某种原因您似乎将整个 row在双引号中,这对于 CSV 来说是不正常的。请edit您的问题以显示示例两行输入和相应的所需输出。
  • 我想我的意思是它转义了它们,这样它就不会导致它似乎在最终输出中引起的确切问题。我已经编辑了这个问题,以便更清楚我在用“row”变量做什么。 (如果你看不到循环,它的名字有点不好)。我查看了CSV spec,看起来双引号内的双引号需要作为两个双引号来完成。所以,“你好,”“再见”,是一个字符串”。但是用两个双引号替换双引号是可行的,但是我的输出现在有两个双引号...
  • 好吧,没关系。我想到了。原来我运行了两次 sanitizeString() 函数。同样,根据 CSV 规范,带引号的列中的双引号需要表示为两个双引号 ("")。我运行了两次该函数,产生了 4 个双引号,转换为两个。

标签: javascript csv comma double-quotes suitescript2.0


【解决方案1】:

事实证明,根据CSV specs,要在已引用的字符串中包含双引号,您需要使用两个双引号(“”)。我改变了:

itemDesc = itemDesc.replace(/"/g, '\"');

itemDesc = itemDesc.replace(/"/g, '""');

我也删除了

itemDesc = itemDesc.replace(/,/g, '\,');
itemDesc = itemDesc.replace(/'/g, '\'');

由于 CSV 中的列已被引用。这些都是不必要的。

【讨论】:

  • 边缘情况,如果字符串不以引号开头,则可以包含引号,例如Yes "" I am。如果它以引号开头,则必须以引号结尾。即使没有引用该术语,也必须对引号进行转义。有趣。
【解决方案2】:

我使用这个简单的函数将 string[][] 转换为 csv 文件。如果单元格包含", 或其他空格(空格除外),它会引用单元格:

/**
 * Takes an array of arrays and returns a `,` sparated csv file.
 * @param {string[][]} table
 * @returns {string}
 */
export function toCSV(table: string[][]) {
    return table
        .map(row =>
            row
                .map(cell => {
                    // We remove blanks and check if the column contains
                    // other whitespace,`,` or `"`.
                    // In that case, we need to quote the column.
                    if (cell.replace(/ /g, '').match(/[\s,"]/)) {
                        return '"' + cell.replace(/"/g, '""') + '"';
                    }
                    return cell;
                })
                .join(',')
        )
        .join('\n');
}

【讨论】:

    【解决方案3】:

    就我而言,我不想引用不需要引用的字符串。所以我在引用之前测试了字符串是否有讨厌的字符。

    function escapeCSV (term) {
      if (term.match && term.match(/,|"/))  {
        return `"${term.replace('"','""')}"`
      } else {
        return term
      }
    }
    

    【讨论】:

    • 小心:replace 只会替换第一次出现。使用带有 g 修饰符 (/"/g) 或新的 replaceAll 函数的正则表达式。
    猜你喜欢
    • 2016-04-15
    • 1970-01-01
    • 1970-01-01
    • 2020-06-09
    • 2016-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多