Excel 表格大冒险:合并行与换行表头的奇幻之旅
有一天,小鹿接到了一个艰巨的任务:从一个充满魔法的 Excel 表格中导入数据到神秘的系统中。这个表格不仅藏有宝贵的设备信息,还布满了各种奇奇怪怪的障碍,比如合并行和换行表头。小鹿心中暗自嘀咕:“这表格是要考考我的耐心吗?”
第一步:揭开合并行的秘密
小鹿打开 Excel 表格,眼前一亮——表格的第一行竟然被施了魔法,变成了合并行!小鹿心想:“这看起来像是一个合并单元格的陷阱。” 她决定先找出所有合并单元格,确保它们不会在数据导入的过程中搞鬼。
她开始编写代码,获取合并单元格的信息:
const merges = workSheet['!merges'];
console.log("合并单元格信息------------", merges);
小鹿在控制台中看到了一长串合并单元格的坐标,心想:“这表格的魔术师真能搞事,竟然有这么多合并单元格!” 小鹿决定先把这些合并单元格的值填充到所有被合并的单元格中,以免数据出现混乱。
第二步:处理换行符的魔法
小鹿继续查看表格,发现表头的列名也被施了魔法,竟然有换行符!她心想:“这表格的魔术师真是无所不用其极,连列名都要搞个花活。” 她决定在获取列名时,截取到换行符之前的部分,确保列名的整洁。
const headers = [];
for (let C = range.s.c; C <= range.e.c; C++) {
const cell = workSheet[XLSX.utils.encode_cell({ r: range.s.r, c: C })];
if (cell && cell.v !== undefined) {
headers.push(cell.v.replace(/↵/g, '\n').trim().split('\n')[0]); // 截取到换行符之前的部分
} else {
headers.push('');
}
}
console.log("处理后的列名------------", headers);
小鹿在控制台中看到了处理后的列名,终于舒了一口气:“这下表头的魔法被破除了,看起来正常多了。”
第三步:填充空数据的空想
小鹿接着开始填充初始数据数组。小鹿心想:“如果表格中有空数据,那我可得小心了,不能让空数据搞乱了整个表格。” 她决定在填充数据时,如果单元格为空,则填充为空字符串 '',确保数据结构的一致性。
for (let R = range.s.r + 1; R <= range.e.r; ++R) { // 从第二行开始,跳过标题行
for (let C = range.s.c; C <= range.e.c; ++C) {
const cell = workSheet[XLSX.utils.encode_cell({ r: R, c: C })];
if (cell && cell.v !== undefined) {
initialData[R][C] = cell.v;
} else {
initialData[R][C] = ''; // 如果单元格为空,则填充为空字符串
}
}
}
console.log("填充后的数据数组------------", initialData);
小鹿在控制台中看到填充后的数据数组,心想:“这下空数据的空想被粉碎了,表格看起来更整齐了。”
第四步:魔法反击
小鹿决定反击这些合并单元格的魔法。她编写代码,将合并单元格的第一个单元格的值应用到所有被合并的单元格中,确保数据的完整性。
if (merges) {
merges.forEach(merge => {
const startRow = merge.s.r;
const startCol = merge.s.c;
const endRow = merge.e.r;
const endCol = merge.e.c;
// 获取合并单元格的第一个单元格的值
const firstCellValue = initialData[startRow][startCol];
// 将这个值应用到所有被合并的单元格中
for (let r = startRow; r <= endRow; r++) {
for (let c = startCol; c <= endCol; c++) {
if (initialData[r][c] === '') {
initialData[r][c] = firstCellValue;
}
}
}
});
}
console.log("处理合并单元格后的数据数组------------", initialData);
小鹿在控制台中看到处理合并单元格后的数据数组,心想:“这下这些合并单元格的魔法都失效了,表格终于恢复正常了!”
第五步:数据转换的奇幻变身
小鹿最后将二维数组转换为 JSON 格式的数组,确保数据在后续处理中更加方便。她心想:“这最后一步真是画龙点睛,数据终于变成了我可以理解的格式。”
const data = [];
for (let R = range.s.r + 1; R < numRows; R++) { // 从第二行开始,跳过标题行
const rowData = {};
for (let C = range.s.c; C <= range.e.c; C++) {
const cellValue = initialData[R][C];
if (cellValue !== '') {
const header = headers[C];
if (header) {
rowData[header] = cellValue;
}
}
}
// 过滤掉空行
if (Object.keys(rowData).length > 0) {
data.push(rowData);
}
}
console.log("导入数据------------1114----------", data);
return data;
小鹿在控制台中看到最终的 JSON 格式数据,心想:“这表格的魔术师真是白费心机了,我终于成功导入数据了!”
小鹿的代码总结
以下是小鹿最终的 getXlsxData 函数代码,确保在处理列名和合并单元格时正确填充数据:
const getXlsxData = async (file) => {
const dataBinary = await readFile(file);
const workBook = XLSX.read(dataBinary, { type: 'array' });
const workSheet = workBook.Sheets[workBook.SheetNames[0]];
// 获取合并单元格的信息
const merges = workSheet['!merges'];
console.log("合并单元格信息------------", merges);
// 获取工作表的行数和列数
const range = XLSX.utils.decode_range(workSheet['!ref']);
const numRows = range.e.r + 1;
const numCols = range.e.c + 1;
// 初始化一个二维数组来存储数据
const initialData = Array.from({ length: numRows }, () => Array(numCols).fill(''));
console.log("初始化后的数据数组------------", initialData);
// 获取列名,并处理换行符
const headers = [];
for (let C = range.s.c; C <= range.e.c; C++) {
const cell = workSheet[XLSX.utils.encode_cell({ r: range.s.r, c: C })];
if (cell && cell.v !== undefined) {
headers.push(cell.v.replace(/↵/g, '\n').trim().split('\n')[0]); // 截取到换行符之前的部分
} else {
headers.push('');
}
}
console.log("处理后的列名------------", headers);
// 填充初始数据数组
for (let R = range.s.r + 1; R <= range.e.r; ++R) { // 从第二行开始,跳过标题行
for (let C = range.s.c; C <= range.e.c; ++C) {
const cell = workSheet[XLSX.utils.encode_cell({ r: R, c: C })];
if (cell && cell.v !== undefined) {
initialData[R][C] = cell.v;
} else {
initialData[R][C] = ''; // 如果单元格为空,则填充为空字符串
}
}
}
console.log("填充后的数据数组------------", initialData);
// 处理合并单元格
if (merges) {
merges.forEach(merge => {
const startRow = merge.s.r;
const startCol = merge.s.c;
const endRow = merge.e.r;
const endCol = merge.e.c;
// 获取合并单元格的第一个单元格的值
const firstCellValue = initialData[startRow][startCol];
// 将这个值应用到所有被合并的单元格中
for (let r = startRow; r <= endRow; r++) {
for (let c = startCol; c <= endCol; c++) {
if (initialData[r][c] === '') {
initialData[r][c] = firstCellValue;
}
}
}
});
}
console.log("处理合并单元格后的数据数组------------", initialData);
// 将二维数组转换为 JSON 格式的数组
const data = [];
for (let R = range.s.r + 1; R < numRows; R++) { // 从第二行开始,跳过标题行
const rowData = {};
for (let C = range.s.c; C <= range.e.c; C++) {
const cellValue = initialData[R][C];
if (cellValue !== '') {
const header = headers[C];
if (header) {
rowData[header] = cellValue;
}
}
}
// 过滤掉空行
if (Object.keys(rowData).length > 0) {
data.push(rowData);
}
}
console.log("导入数据------------1114----------", data);
return data;
};