基于node編寫excel讀取和導出的小工具
背景
領導給同事安排了一個體力活,根據(jù)表1(7k+條)篩選表2(4W+條),然后合并兩個表相同的數(shù)據(jù)。聽起來是挺簡單的需求,加個外表篩選就完事了么,基礎的excel操作他還是會的,但是仔細研究了下,發(fā)現(xiàn)行不通,F(xiàn)ILTER和MATCH都會有一定的局限。并且最后的和并新表也是個困難。于是來求助,看能不能寫個小腳本,跑一下解決問題。 我了解了下需求,覺得可行,于是便有了這個腳本
需求描述
表1格式
| 姓名 | 年齡 | 住址 |
|---|---|---|
| 張三 | 20 | 上海外灘18號 |
| 李四 | 21 | 上海浦東新區(qū) |
| 王五 | 22 | 御青路1號 |
| 。。。 | 。。。 | 。。。 |
表2格式
| 昵稱 | 注冊時間 | 住址 |
|---|---|---|
| 二蛋 | 2021 | 18號 |
| 雙下巴大圓臉 | 2015 | 上海 |
| 狗子 | 2022 | 御青路 |
| 。。。 | 。。。 | 。。。 |
他的需求,就是根據(jù)表2的住址模糊篩選出表格1住址列所有匹配的數(shù)據(jù)。然后合并信息。
介紹結束、開始碼代碼
1、 node讀取excel并解析數(shù)據(jù)
我這里是用了node的xlsx
// 安裝xlsx npm install --save xlsx
xlsx本身提供了一個讀取文件方法,就不需要用fs的讀取了,核心代碼如下
const workbook = xlsx.readFile(filePath); // 我這里只需要第一個,對于多個sheet的情況,這里加個循環(huán)就好了 const sheetName = workbook.SheetNames[0]; const sheet = workbook.Sheets[sheetName]; // 將表內容轉換為 JSON 數(shù)據(jù) const data = xlsx.utils.sheet_to_json(sheet);
這里推薦使用vscode的調試模式,可以很方便的查看變量的實際值,不用console一遍一遍查看

2、 過濾數(shù)據(jù),并合并需要的數(shù)據(jù)
拿到表1和表2的數(shù)據(jù)后,就是過濾數(shù)據(jù)的邏輯了
// 過濾文件
const processingData = ({filterFileData,resourceFileData}) => {
// 創(chuàng)建一個包含所有 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
}對于這種大數(shù)據(jù)過濾,盡可能的減少循環(huán)套循環(huán),我這里是直接把表2住址拼接了一個正則,用match去校驗表1的地址列,是否包含表2字符串,有更好的方案,可以在評論區(qū)打出來交流下
3、 導出excel
在第二步,我把匹配成功的表1和表2數(shù)據(jù)都存在了一個數(shù)組,然后再第三步使用,這里就是拼數(shù)據(jù)和寫數(shù)據(jù)了
// 生成篩選后的excel
const writeExcel = ({writeData,resourceFileName}) => {
const data = writeData.map((item, index) => {
const {filterFileData,resourceFileData} = item
return {
'序號': index + 1,
'所屬區(qū)縣': filterFileData['所屬區(qū)縣'],
'戶號': resourceFileData['戶號'],
'戶名': resourceFileData['戶名'],
'戶號地址': resourceFileData['地址'],
'機構全稱': filterFileData['機構全稱'],
'機構類型': filterFileData['機構類型'],
'機構地址': filterFileData['地址'],
}
})
// 將數(shù)據(jù)轉換為 worksheet
const worksheet = xlsx.utils.json_to_sheet(data);
// 創(chuàng)建一個新的 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、過濾源數(shù)據(jù)
// 3、將過濾好的數(shù)據(jù),寫入一個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 數(shù)據(jù)
const data = xlsx.utils.sheet_to_json(sheet);
resolve(data);
});
};
// 過濾文件
const processingData = ({filterFileData,resourceFileData}) => {
// 創(chuàng)建一個包含所有 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,
'所屬區(qū)縣': filterFileData['所屬區(qū)縣'],
'戶號': resourceFileData['戶號'],
'戶名': resourceFileData['戶名'],
'戶號地址': resourceFileData['地址'],
'機構全稱': filterFileData['機構全稱'],
'機構類型': filterFileData['機構類型'],
'機構地址': filterFileData['地址'],
}
})
// 將數(shù)據(jù)轉換為 worksheet
const worksheet = xlsx.utils.json_to_sheet(data);
// 創(chuàng)建一個新的 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}`)
// 讀取待篩選數(shù)據(jù)
let resourceFile = await readFile(
path.resolve(resourceFileDirPath, fileName)
);
console.log(`讀取文件成功,正在解析文件`)
// 解析文件
const writeData = processingData({
filterFileData: filterFile,
resourceFileData: resourceFile,
})
console.log(`解析文件成功,正在導出文件`)
// 寫入數(shù)據(jù)
writeExcel({
writeData,
resourceFileName: fileName
})
console.timeEnd(`${fileName}用時:`);
}
console.timeEnd("總用時");
};
// 執(zhí)行
try {
main();
} catch (error) {
console.log('error',error)
}結語
感覺沒有合并這個要求的話,excel是不是可以直接篩選出來了?對excel函數(shù)不熟悉,嘗試了幾下沒有實現(xiàn)。
到此這篇關于基于node編寫excel讀取和導出的小工具的文章就介紹到這了,更多相關node excel讀取和導出內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Node.js使用sharp庫實現(xiàn)PNG圖片轉換為WebP格式
在 Node.js 中,可以使用 sharp 庫將 PNG 圖片轉換為 WebP 格式,sharp 是一個高性能的圖像處理庫,支持多種圖像格式的轉換和處理,以下是如何使用 sharp 將 PNG 圖片轉換為 WebP 的詳細步驟,需要的朋友可以參考下2024-12-12
Node.js實現(xiàn)前端后端數(shù)據(jù)傳輸加密解密
這篇文章主要介紹了Node.js實現(xiàn)前端后端數(shù)據(jù)傳輸加密解密,文章圍繞主題展開詳細的內容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-08-08

