You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Google Apps Script解析含双引号与?的Gmail附件CSV问题

问题背景

我通过以下代码实现将CSV解析到指定Google表格的流程:

function updateGmvAndNmv() {
  const threads = GmailApp.search("from:(sender@xxx.de) subject:(uniqueHeader)");
  const messages = threads[0].getMessages();
  const length = messages.length;
  const lastMessage = messages[length - 1];
  const attachemnt = lastMessage.getAttachments()[0];

  const csvData = Utilities.parseCsv(attachemnt.getDataAsString(), ",");

  const ss = SpreadsheetApp.openById("spreadsheetID").getSheetByName("sheetName")
  const ssOriginalRange = ss.getRange("A:E");
  const ssToPaste = ss.getRange(1,1,csvData.length,csvData[0].length);

  ssOriginalRange.clear();
  ssToPaste.setValues(csvData)
}

近期解析一份新CSV时遇到问题,且无法修改该CSV的生成规则。用文本编辑器查看该CSV内容如下:

GMV and NMV per partner

"Merchant",,"NMV","GMV bef Cancellation","GMV bef Return"

运行代码后表格输出异常,现咨询以下技术问题:

  1. 为何行5仍保留双引号?原以为parseCsv函数会自动去除;
  2. 带双引号与不带双引号的CSV存在哪些差异?此前解析无引号的CSV未出现问题;
  3. 如何正确处理数据,使表格中不显示双引号?
  4. 行1和7的fx输入框中出现?符号的原因是什么?如何去除?文本编辑器中查看CSV无此类符号。

问题解答

1. 为何行5仍保留双引号?

Utilities.parseCsv仅在符合标准CSV格式的前提下自动去除双引号。标准CSV中,双引号的作用是包裹含分隔符(逗号)、换行符或双引号本身的内容,且包裹内容的双引号必须成对、转义正确。

你的CSV出现保留引号的情况,大概率是因为:

  • 部分字段的双引号不完整(单侧引号);
  • CSV编码异常,导致getDataAsString()读取时将引号识别为普通字符;
  • 字段内的引号未按规则转义(比如单独出现"而非"")。
    以上情况都会让解析器把双引号当作字段内容的一部分,而非格式符号。

2. 带双引号与不带双引号的CSV差异

  • 内容限制差异:
    • 无引号CSV:字段内容不能包含逗号、换行符或双引号,否则会被解析器误判为分隔符或格式错误;
    • 带引号CSV:用双引号包裹后,字段内可合法包含逗号、换行符;若字段内需要双引号,需写成连续两个双引号(""),解析后会转为单个双引号。
  • 解析逻辑差异:
    • 无引号字段:解析器直接按分隔符拆分字符串;
    • 带引号字段:解析器识别成对双引号,仅提取引号内的内容(自动去除包裹引号),但引号格式不规范时该逻辑失效。

你之前解析无引号CSV正常,是因为数据本身无特殊字符,符合简单CSV的解析规则。

3. 如何正确处理数据去除双引号?

可以在解析后遍历所有数据,手动去除字段首尾的双引号,同时处理转义的双引号(""转成")。修改后的代码如下:

function updateGmvAndNmv() {
  const threads = GmailApp.search("from:(sender@xxx.de) subject:(uniqueHeader)");
  const messages = threads[0].getMessages();
  const lastMessage = messages[messages.length - 1];
  const attachment = lastMessage.getAttachments()[0];

  let csvData = Utilities.parseCsv(attachment.getDataAsString(), ",");
  
  // 处理双引号:去除首尾引号,转义""为"
  csvData = csvData.map(row => {
    return row.map(cell => {
      let processed = cell.replace(/^"|"$/g, '');
      processed = processed.replace(/""/g, '"');
      return processed;
    });
  });

  const ss = SpreadsheetApp.openById("spreadsheetID").getSheetByName("sheetName");
  const ssOriginalRange = ss.getRange("A:E");
  const ssToPaste = ss.getRange(1, 1, csvData.length, csvData[0].length);

  ssOriginalRange.clear();
  ssToPaste.setValues(csvData);
}

代码通过正则表达式批量处理单元格:

  • ^"|"$匹配单元格首尾的双引号并替换为空;
  • ""替换为单个双引号,处理CSV中的转义逻辑。

4. fx输入框中出现?符号的原因及解决方法

这个?是不可见控制字符,主要由CSV编码问题导致:

  • 常见原因:CSV使用带BOM(字节顺序标记)的编码(如UTF-8 BOM),getDataAsString()读取时会将BOM字符(\ufeff)当作普通文本,显示为不可见的?;
  • 次要原因:CSV包含其他非打印ASCII字符(如异常换行符、制表符)。

解决方法是在读取CSV内容时去除BOM和不可见字符,修改读取数据的代码段:

// 替换原解析前的内容
let csvContent = attachment.getDataAsString();
// 去除UTF-8 BOM字符
csvContent = csvContent.replace(/^\ufeff/, '');
// 去除其他不可见控制字符(可选)
csvContent = csvContent.replace(/[\x00-\x1F\x7F]/g, '');
const csvData = Utilities.parseCsv(csvContent, ",");

结合之前的双引号处理逻辑,即可同时解决两个问题。


内容的提问来源于stack exchange,提问作者Binchentso

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 07:54:22