移除邮箱列表中的‘复杂重复项’技术解决方案问询
如何修改Google Sheets去重脚本以识别同一用户的邮箱变体重复项?
这是个很常见的邮箱去重场景——很多邮箱服务商允许用户在本地部分用.、-、_做分隔,实际却指向同一个收件箱。要解决这个问题,核心是给每个邮箱生成一个标准化的唯一标识,让所有变体都映射到同一个值,然后用这个标识来判断重复。
先看你的问题背景:
我在处理邮箱列表时遇到如下问题:同一用户存在多种格式的重复邮箱地址,例如Jane的邮箱包含
jane.doe@email.com、doe.jane@email.com等变体,还包括用-或_替换.的情况。目前我使用的由@Jordan Running和Ed Nelson协助升级的去重脚本仅能处理"严格重复项",无法识别此类"复杂重复项"。请问如何修改脚本,确保同一用户仅保留一个指向同一收件箱的邮箱地址?
你当前使用的代码:
function removeDuplicates() { const startTime = new Date(); const newData = []; const sheet = SpreadsheetApp.getActiveSheet(); const data = sheet.getDataRange().getValues(); const numRows = data.length; const seen = {}; for (var i = 0, row, key; i < numRows && (row = data[i]); i++) { key = JSON.stringify(row); if (key in seen) { continue; } seen[key] = true; newData.push(row); }; sheet.clearContents(); sheet.getRange(1, 1, newData.length, newData[0].length).setValues(newData); // Show summary const secs = (new Date() - startTime) / 1000; SpreadsheetApp.getActiveSpreadsheet().toast( Utilities.formatString('Processed %d rows in %.2f seconds (%.1f rows/sec); %d deleted', numRows, secs, numRows / secs, numRows - newData.length), 'Remove duplicates', -1); }
解决方案:添加邮箱标准化逻辑
1. 核心思路
我们需要新增一个邮箱标准化函数,把所有变体转换成统一格式:
- 邮箱地址不区分大小写,先转成小写
- 把本地部分(@符号之前的内容)的
.、-、_全部移除(因为这些符号在多数邮箱服务商中不影响收件) - 域名部分保持不变(域名的符号不能随意修改)
2. 修改后的完整脚本
function removeDuplicates() { const startTime = new Date(); const newData = []; const sheet = SpreadsheetApp.getActiveSheet(); const data = sheet.getDataRange().getValues(); const numRows = data.length; const seenEmails = {}; // 👉 这里修改邮箱所在的列索引:A列=0,B列=1,C列=2,以此类推 const EMAIL_COLUMN_INDEX = 1; // 邮箱标准化函数:把所有变体转换成统一格式 function normalizeEmail(email) { if (!email || typeof email !== 'string') return email; const emailLower = email.toLowerCase(); const atIndex = emailLower.indexOf('@'); if (atIndex === -1) return emailLower; // 无效邮箱(无@)直接返回小写 const localPart = emailLower.slice(0, atIndex); const domain = emailLower.slice(atIndex); // 移除本地部分的所有.、-、_符号 const normalizedLocal = localPart.replace(/[._-]/g, ''); return `${normalizedLocal}${domain}`; } for (var i = 0, row, email, normalizedEmail; i < numRows && (row = data[i]); i++) { email = row[EMAIL_COLUMN_INDEX]; normalizedEmail = normalizeEmail(email); // 表头行直接保留,不参与重复判断 if (i === 0) { newData.push(row); seenEmails[normalizedEmail] = true; continue; } // 如果这个标准化邮箱已经出现过,跳过当前行 if (normalizedEmail in seenEmails) { continue; } seenEmails[normalizedEmail] = true; newData.push(row); }; sheet.clearContents(); sheet.getRange(1, 1, newData.length, newData[0].length).setValues(newData); // 显示处理总结 const secs = (new Date() - startTime) / 1000; SpreadsheetApp.getActiveSpreadsheet().toast( Utilities.formatString('Processed %d rows in %.2f seconds (%.1f rows/sec); %d deleted', numRows, secs, numRows / secs, numRows - newData.length), 'Remove duplicates', -1); }
3. 关键修改说明
- 邮箱列配置:通过
EMAIL_COLUMN_INDEX变量指定邮箱所在的列,根据你的表格调整即可 - 标准化函数:
normalizeEmail会把jane.doe@email.com、jane-doe@email.com、Jane_Doe@Email.COM全部转换成janedoe@email.com,这样所有变体都会被识别为同一个邮箱 - 表头处理:特意保留了第一行(表头)的逻辑,避免表头被误判为重复项
- 无效邮箱兼容:对于没有
@的无效邮箱,脚本会转成小写后作为唯一标识,不会误删
4. 自定义调整建议
如果你需要优先保留特定格式的邮箱(比如优先保留带.的原始版本),可以调整循环逻辑:先遍历所有行,为每个标准化邮箱记录第一次出现的行(或者你偏好的行),最后再把这些行写入表格。
内容的提问来源于stack exchange,提问作者Ed Dev
相关产品推荐
相关产品推荐

