使用GAS导出Gmail表格至Google Sheets,如何保留合并单元格格式?
解决Gmail带合并单元格表格提取到Google Sheets的问题
原代码通过正则替换HTML标签的方式处理表格,会丢失colspan(跨列)和rowspan(跨行)属性,导致合并单元格的格式无法保留。需要改用DOM解析的方式处理HTML表格,提取合并属性后重构表格结构,同时在Sheet中还原合并格式。
修改后的完整代码
var SEARCH_QUERY = "SearchKey"; function getEmailss_(q) { var emails = []; var threads = GmailApp.search(q); if (threads.length === 0) { console.log("未找到匹配搜索条件的邮件线程: " + q); return []; } for (var threadIdx = 0; threadIdx < threads.length; threadIdx++) { var msgs = threads[threadIdx].getMessages(); for (var msgIdx = 0; msgIdx < msgs.length; msgIdx++) { var htmlBody = msgs[msgIdx].getBody(); // 用HtmlService解析HTML,避免正则的局限性 var doc = HtmlService.createHtmlOutput(htmlBody).getContent(); var table = extractFirstTable(doc); // 提取第一个表格,可根据需求调整 if (!table) { console.log("当前邮件未找到表格: " + threads[threadIdx].getFirstMessageSubject()); continue; } // 处理表格的合并单元格,生成结构化数组和合并信息 var { tableData, merges } = processMergedCells(table); emails.push({ data: tableData, merges: merges }); } } if (emails.length === 0) { console.log("未找到包含表格的匹配邮件: " + q); return []; } // 这里假设只处理第一个邮件的表格,可根据需求调整为合并多个邮件的表格 return emails[0]; } // 从HTML中提取第一个<table>元素 function extractFirstTable(html) { var tempDiv = document.createElement('div'); tempDiv.innerHTML = html; return tempDiv.querySelector('table'); } // 处理合并单元格,返回表格数据和合并信息 function processMergedCells(table) { var rows = table.querySelectorAll('tr'); var tableData = []; var merges = []; // 用于跟踪跨行单元格的剩余行数 var rowSpanTracker = []; for (var rowIdx = 0; rowIdx < rows.length; rowIdx++) { var row = rows[rowIdx]; var cells = row.querySelectorAll('td, th'); var currentRow = []; var colIdx = 0; // 先处理跨行剩余的单元格 while (rowSpanTracker[colIdx]) { currentRow.push(rowSpanTracker[colIdx].value); rowSpanTracker[colIdx].remaining--; if (rowSpanTracker[colIdx].remaining === 0) { rowSpanTracker[colIdx] = null; } colIdx++; } for (var cellIdx = 0; cellIdx < cells.length; cellIdx++) { var cell = cells[cellIdx]; var cellText = cell.textContent.trim().replace(/\s+/g, ' '); var colspan = parseInt(cell.getAttribute('colspan')) || 1; var rowspan = parseInt(cell.getAttribute('rowspan')) || 1; // 填充当前单元格的跨列 for (var c = 0; c < colspan; c++) { currentRow.push(cellText); // 如果跨行大于1,记录到跟踪器 if (rowspan > 1) { rowSpanTracker[colIdx + c] = { value: cellText, remaining: rowspan - 1 }; } } colIdx += colspan; // 记录合并信息(格式:[起始行, 起始列, 结束行, 结束列],注意Sheet的行列是从1开始) if (colspan > 1 || rowspan > 1) { merges.push([ rowIdx + 1, // 起始行(Sheet行号从1开始) colIdx - colspan + 1, // 起始列 rowIdx + rowspan, // 结束行 colIdx - colspan + colspan // 结束列 ]); } } // 填充行尾可能的空单元格(如果有跨行跟踪器的后续列) while (rowSpanTracker[colIdx]) { currentRow.push(rowSpanTracker[colIdx].value); rowSpanTracker[colIdx].remaining--; if (rowSpanTracker[colIdx].remaining === 0) { rowSpanTracker[colIdx] = null; } colIdx++; } tableData.push(currentRow); } return { tableData, merges }; } function appendData_(sheet, tableInfo) { var tableData = tableInfo.data; var merges = tableInfo.merges; var h = tableData.length; if (h === 0) return; var l = tableData[0].length; // 清空原有内容和合并格式 sheet.clear(); // 写入表格数据 sheet.getRange(1, 1, h, l).setValues(tableData); // 应用合并单元格格式 merges.forEach(merge => { sheet.getRange(merge[0], merge[1], merge[2] - merge[0] + 1, merge[3] - merge[1] + 1).merge(); }); } function saveEmailsss() { var tableInfo = getEmailss_(SEARCH_QUERY); if (tableInfo && tableInfo.data.length > 0) { appendData_(SpreadsheetApp.getActive().getSheetByName('Sheet1'), tableInfo); } markArchivedAsRead(); } function markArchivedAsRead() { var threads = GmailApp.search('label:inbox is:unread to:me subject:importnumberlist'); GmailApp.markThreadsRead(threads); };
关键修改说明
- 改用DOM解析:放弃正则替换,使用
HtmlService和DOM API解析HTML表格,能准确读取colspan和rowspan属性。 - 跨行跟踪机制:通过
rowSpanTracker数组记录跨行单元格的剩余行数,确保后续行自动填充合并单元格的内容。 - 还原合并格式:提取合并信息后,在写入Sheet时调用
merge()方法还原邮件中的合并单元格格式。 - 鲁棒性优化:增加了未找到表格、邮件线程的日志提示,避免空数据导致的错误。
内容的提问来源于stack exchange,提问作者Gitz
相关产品推荐
相关产品推荐

