使用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"
运行代码后表格输出异常,现咨询以下技术问题:
- 为何行5仍保留双引号?原以为
parseCsv函数会自动去除; - 带双引号与不带双引号的CSV存在哪些差异?此前解析无引号的CSV未出现问题;
- 如何正确处理数据,使表格中不显示双引号?
- 行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
相关产品推荐
相关产品推荐

