从 wps 复制文档,获取到如下 html 表格, 计算表格每列的宽度后,插入 colgroup>col[width="61"] 标签用于控制表格每列宽度。 Snipaste_2024-10-12_14-32-02.png <table> <tbody> <tr> <td width="61" colspan="1" rowspan="1"></td> <td width="723" colspan="7" rowspan="1"></td> </tr> <tr> <td width="61" colspan="1" rowspan="1"></td> <td width="723" colspan="7" rowspan="1"></td> </tr> <tr> <td width="61" colspan="1" rowspan="1"></td> <td width="723" colspan="7" rowspan="1"></td> </tr> <tr> <td width="61" colspan="1" rowspan="2"></td> <td width="91" colspan="1" rowspan="1"></td> <td width="106" colspan="1" rowspan="1"></td> <td width="47" colspan="1" rowspan="1"></td> <td width="84" colspan="1" rowspan="1"></td> <td width="394" colspan="3" rowspan="1"></td> </tr> <tr> <td width="91" colspan="1" rowspan="1"></td> <td width="106" colspan="1" rowspan="1"></td> <td width="47" colspan="1" rowspan="1"></td> <td width="84" colspan="1" rowspan="1"></td> <td width="394" colspan="3" rowspan="1"></td> </tr> <tr> <td width="61" colspan="1" rowspan="2"></td> <td width="723" colspan="7" rowspan="1"></td> </tr> <tr> <td width="723" colspan="7" rowspan="1"></td> </tr> <tr> <td width="61" colspan="1" rowspan="1"></td> <td width="337" colspan="5" rowspan="1"></td> <td width="65" colspan="1" rowspan="1"></td> <td width="320" colspan="1" rowspan="1"></td> </tr> </tbody> </table> 转化为下面的数据结构 type TdAttr = { width: number; colspan: number; rowspan: number } const tdAttr: TdAttr[][] = [ [ { width: 61, colspan: 1, rowspan: 1 }, { width: 723, colspan: 7, rowspan: 1 } ], [ { width: 61, colspan: 1, rowspan: 1 }, { width: 723, colspan: 7, rowspan: 1 } ], [ { width: 61, colspan: 1, rowspan: 1 }, { width: 723, colspan: 7, rowspan: 1 } ], [ { width: 61, colspan: 1, rowspan: 2 }, { width: 91, colspan: 1, rowspan: 1 }, { width: 106, colspan: 1, rowspan: 1 }, { width: 47, colspan: 1, rowspan: 1 }, { width: 84, colspan: 1, rowspan: 1 }, { width: 394, colspan: 3, rowspan: 1 } ], [ { width: 91, colspan: 1, rowspan: 1 }, { width: 106, colspan: 1, rowspan: 1 }, { width: 47, colspan: 1, rowspan: 1 }, { width: 84, colspan: 1, rowspan: 1 }, { width: 394, colspan: 3, rowspan: 1 } ], [ { width: 61, colspan: 1, rowspan: 2 }, { width: 723, colspan: 7, rowspan: 1 } ], [ { width: 723, colspan: 7, rowspan: 1 } ], [ { width: 61, colspan: 1, rowspan: 1 }, { width: 337, colspan: 5, rowspan: 1 }, { width: 65, colspan: 1, rowspan: 1 }, { width: 320, colspan: 1, rowspan: 1 } ] ] 算法如下 function calculateColumnWidths(tds: TdAttr[][]) { // 列数 const columnCount = tds[0].reduce((acc, cell) => acc + cell.colspan, 0) // 定义 dp[i][j] 表示 i 到 j 列的宽度,初始值为 0。(从 0 开始计数列数) const dp = Array.from({ length: columnCount }, () => new Array<number>(columnCount).fill(0)) // 用于记录每列被跨行占据的行数 const occupied = new Array(columnCount).fill(0) // 填充 dp for (const row of tds) { let currentColumnIndex = 0 const minRowspan = Math.min(...row.map(it => it.rowspan)) for (const cell of row) { while (currentColumnIndex < columnCount && occupied[currentColumnIndex] > 0) { occupied[currentColumnIndex] -= minRowspan currentColumnIndex++ } if (cell.rowspan > minRowspan) { for (let i = 0; i < cell.colspan; i++) { occupied[currentColumnIndex + i] = cell.rowspan - minRowspan } } if (currentColumnIndex + cell.colspan - 1 >= columnCount) break dp[currentColumnIndex][currentColumnIndex + cell.colspan - 1] = cell.width currentColumnIndex += cell.colspan } } // 计算 dp for (let k = 0; k < (columnCount * columnCount) / 2; k++) { for (let len = 1; len < columnCount; len++) { for (let i = 0; i + len < columnCount; i++) { let j = i + len if (dp[i][j] == 0 && dp[i][j - 1] != 0 && dp[j][j] != 0) { dp[i][j] = dp[i][j - 1] + dp[j][j] } if (dp[i][j - 1] == 0 && dp[i][j] != 0 && dp[j][j] != 0) { dp[i][j - 1] = dp[i][j] - dp[j][j] } if (dp[j][j] == 0 && dp[i][j] != 0 && dp[i][j - 1] != 0) { dp[j][j] = dp[i][j] - dp[i][j - 1] } } } } return dp.map((it, index) => it[index]) }