基于node编写excel读取和导出的小工具
作者:双下巴大圆脸
这篇文章主要为大家详细介绍了如何基于node编写一个小工具,可以实现excel读取和导出,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下
背景
领导给同事安排了一个体力活,根据表1(7k+条)筛选表2(4W+条),然后合并两个表相同的数据。听起来是挺简单的需求,加个外表筛选就完事了么,基础的excel操作他还是会的,但是仔细研究了下,发现行不通,FILTER和MATCH都会有一定的局限。并且最后的和并新表也是个困难。于是来求助,看能不能写个小脚本,跑一下解决问题。 我了解了下需求,觉得可行,于是便有了这个脚本
需求描述
表1格式
姓名 | 年龄 | 住址 |
---|---|---|
张三 | 20 | 上海外滩18号 |
李四 | 21 | 上海浦东新区 |
王五 | 22 | 御青路1号 |
。。。 | 。。。 | 。。。 |
表2格式
昵称 | 注册时间 | 住址 |
---|---|---|
二蛋 | 2021 | 18号 |
双下巴大圆脸 | 2015 | 上海 |
狗子 | 2022 | 御青路 |
。。。 | 。。。 | 。。。 |
他的需求,就是根据表2的住址模糊筛选出表格1住址列所有匹配的数据。然后合并信息。
介绍结束、开始码代码
1、 node读取excel并解析数据
我这里是用了node的xlsx
// 安装xlsx npm install --save xlsx
xlsx本身提供了一个读取文件方法,就不需要用fs的读取了,核心代码如下
const workbook = xlsx.readFile(filePath); // 我这里只需要第一个,对于多个sheet的情况,这里加个循环就好了 const sheetName = workbook.SheetNames[0]; const sheet = workbook.Sheets[sheetName]; // 将表内容转换为 JSON 数据 const data = xlsx.utils.sheet_to_json(sheet);
这里推荐使用vscode的调试模式,可以很方便的查看变量的实际值,不用console一遍一遍查看
2、 过滤数据,并合并需要的数据
拿到表1和表2的数据后,就是过滤数据的逻辑了
// 过滤文件 const processingData = ({filterFileData,resourceFileData}) => { // 创建一个包含所有 filterFileData.地址 的正则表达式 const areaPattern = new RegExp(filterFileData.map(item => item['地址']).join('|')); // 记录匹配结果 const matches = resourceFileData.reduce((acc, item2) => { const match = item2['地址'].match(areaPattern); if (match) { // 找到匹配的 arr1 项 const matchedItem1 = filterFileData.find(item1 => item1['地址'] === match[0]); acc.push({ filterFileData: matchedItem1, resourceFileData: item2 }); } return acc; }, []); return matches }
对于这种大数据过滤,尽可能的减少循环套循环,我这里是直接把表2住址拼接了一个正则,用match去校验表1的地址列,是否包含表2字符串,有更好的方案,可以在评论区打出来交流下
3、 导出excel
在第二步,我把匹配成功的表1和表2数据都存在了一个数组,然后再第三步使用,这里就是拼数据和写数据了
// 生成筛选后的excel const writeExcel = ({writeData,resourceFileName}) => { const data = writeData.map((item, index) => { const {filterFileData,resourceFileData} = item return { '序号': index + 1, '所属区县': filterFileData['所属区县'], '户号': resourceFileData['户号'], '户名': resourceFileData['户名'], '户号地址': resourceFileData['地址'], '机构全称': filterFileData['机构全称'], '机构类型': filterFileData['机构类型'], '机构地址': filterFileData['地址'], } }) // 将数据转换为 worksheet const worksheet = xlsx.utils.json_to_sheet(data); // 创建一个新的 workbook,并附加 worksheet const workbook = xlsx.utils.book_new(); xlsx.utils.book_append_sheet(workbook, worksheet, 'Sheet1'); let outputFileName = `${resourceFileName.split('.')[0]}-筛选结果.xlsx` let outputFilePath = path.join(outputFileDirPath,`./${outputFileName}`) // 保存 Excel 文件 xlsx.writeFile(workbook, outputFilePath); console.log(`导出文件成功,地址在:${outputFilePath}`) }
完整代码
// 1、读取filterFile和resourceFile目录下的文件 // 2、过滤源数据 // 3、将过滤好的数据,写入一个excel const fs = require("fs"); const xlsx = require("xlsx"); const path = require("path"); const resourceFileDirPath = path.join(__dirname, "./resourceFile"); const filterFileName = "filter.xlsx"; const filterFileDirPath = path.join(__dirname, `./filterFile/${filterFileName}`); const outputFileDirPath = path.join(__dirname, `./outputFile`); // 读取excel文件 const readFile = (filePath) => { return new Promise((resolve, reject) => { const workbook = xlsx.readFile(filePath); // 暂时只解析第一个sheet const sheetName = workbook.SheetNames[0]; const sheet = workbook.Sheets[sheetName]; // 将表内容转换为 JSON 数据 const data = xlsx.utils.sheet_to_json(sheet); resolve(data); }); }; // 过滤文件 const processingData = ({filterFileData,resourceFileData}) => { // 创建一个包含所有 filterFileData.地址 的正则表达式 const areaPattern = new RegExp(filterFileData.map(item => item['地址']).join('|')); // 记录匹配结果 const matches = resourceFileData.reduce((acc, item2) => { const match = item2['地址'].match(areaPattern); if (match) { // 找到匹配的 arr1 项 const matchedItem1 = filterFileData.find(item1 => item1['地址'] === match[0]); acc.push({ filterFileData: matchedItem1, resourceFileData: item2 }); } return acc; }, []); return matches } // 生成筛选后的excel const writeExcel = ({writeData,resourceFileName}) => { const data = writeData.map((item, index) => { const {filterFileData,resourceFileData} = item return { '序号': index + 1, '所属区县': filterFileData['所属区县'], '户号': resourceFileData['户号'], '户名': resourceFileData['户名'], '户号地址': resourceFileData['地址'], '机构全称': filterFileData['机构全称'], '机构类型': filterFileData['机构类型'], '机构地址': filterFileData['地址'], } }) // 将数据转换为 worksheet const worksheet = xlsx.utils.json_to_sheet(data); // 创建一个新的 workbook,并附加 worksheet const workbook = xlsx.utils.book_new(); xlsx.utils.book_append_sheet(workbook, worksheet, 'Sheet1'); let outputFileName = `${resourceFileName.split('.')[0]}-筛选结果.xlsx` let outputFilePath = path.join(outputFileDirPath,`./${outputFileName}`) // 保存 Excel 文件 xlsx.writeFile(workbook, outputFilePath); console.log(`导出文件成功,地址在:${outputFilePath}`) } const main = async () => { console.time("总用时"); const files = fs.readdirSync(resourceFileDirPath); let filterFile = await readFile(filterFileDirPath); // 过滤掉没有地址 和指定关键字的文件 filterFile = filterFile.filter(item => { let area = item['地址'] let blackList = ['0','无', '无地址'] return area && !blackList.includes(area) }) console.log(files); for (const fileName of files) { console.time(`${fileName}用时:`); console.log(`正在读取文件${fileName}`) // 读取待筛选数据 let resourceFile = await readFile( path.resolve(resourceFileDirPath, fileName) ); console.log(`读取文件成功,正在解析文件`) // 解析文件 const writeData = processingData({ filterFileData: filterFile, resourceFileData: resourceFile, }) console.log(`解析文件成功,正在导出文件`) // 写入数据 writeExcel({ writeData, resourceFileName: fileName }) console.timeEnd(`${fileName}用时:`); } console.timeEnd("总用时"); }; // 执行 try { main(); } catch (error) { console.log('error',error) }
结语
感觉没有合并这个要求的话,excel是不是可以直接筛选出来了?对excel函数不熟悉,尝试了几下没有实现。
到此这篇关于基于node编写excel读取和导出的小工具的文章就介绍到这了,更多相关node excel读取和导出内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!