
文档开发工具CLI【免费下载链接】pandocUniversal markup converter项目地址https://gitcode.com/gh_mirrors/pa/pandoc点击查看免费下载导读AsciiDoc 的表格模型与 Pandoc 内部 AST 模型存在根本差异AsciiDoc 只支持1 个表头行和1 个表尾行而 HTML 与 Pandoc 原生 AST 允许任意多的表头/表尾行、任意跨度的行列合并rowspan/colspan以及空行。这篇指南以仓库中的回归测试 test/command/7326.md 为骨架完整还原 Pandoc 将带行列合并的复杂 HTML 表格与 native 格式表格转换为 AsciiDoc 的全部规则——包括2/.2/a|等 AsciiDoc 单元格语法、多表头表尾行的折叠策略、跨行跨列在表头表尾中的行高调整以及空行的吞并逻辑并深入到 src/Text/Pandoc/Writers/AsciiDoc.hs 中adjustHeaders、adjustFooters、adjustEmptyRows等函数的源码实现让你既会照着写也理解为什么这样写。背景AsciiDoc 表格模型与 Pandoc 的差异Pandoc 的 AsciiDoc 输出器位于 src/Text/Pandoc/Writers/AsciiDoc.hs其模块头部注释直接声明了这种转换的表达力边界见该文件第 15-19 行Note that some information may be lost in conversion, due to expressive limitations of asciidoc. Footnotes and table cells with paragraphs (or other block items) are not possible in asciidoc.也就是说AsciiDoc 无法表达单元格内的多段落/块级内容如嵌套列表、代码块、多表头行、多表尾行。Pandoc 的处理策略是单元格内的多个块使用 AsciiDoc 的a|块单元格语法a即 asciidoc将块内容以 AsciiDoc 源码形式内嵌多个表头/表尾行只保留第一个表头行作为 AsciiDoc 表头、最后一个表尾行作为 AsciiDoc 表尾其余行降级为表体行并通过在对应位置插入空单元格来维持行列布局空行AsciiDoc 无法表达完全无单元格的空行Pandoc 用空行吞并跨行高度adjustEmptyRows的方式将其吸收进相邻单元格的rowspan中。这些行为在 test/command/7326.md 中被完整地固化成了可自动执行的回归测试。命令测试文件7326.md 是什么test/command/7326.md 是 Pandoc 的命令级回归测试issue 7326 对应的测试。这类文件由 test/Tests/Command.hs 驱动执行其格式规范见该文件第 13-31 行注释代码块第一行以%开头是待执行的命令例如% pandoc -f html -t asciidoc之后是作为 stdin 输入传给命令的内容stdin 以单独一行的^D结束^D之后的行是期望的标准输出若有 stderr需以2前缀标注若期望非零退出码最后一行以前缀标注。运行测试时Tests.Command 会把输入喂给test-pandoc --emulate并逐字节比对实际输出与期望输出。7326.md 一共包含7 组场景恰好覆盖了复杂表格转换的全部难点含行和列合并的表格多表头行 多表尾行无表头但含表尾行多表头行场景下的rowspan调整多表尾行场景下的rowspan调整单元格级对齐native 输入空行场景下的rowspan调整及空行的一般处理。下面逐一展开。案例一行/列合并的基本映射colspan 与 rowspan 语法最基础的场景一个带colgroup列宽、colspan跨列、rowspan跨行、单元格内含列表块的 HTML 表格。命令与输入% pandoc -f html -t asciidoc table colgroup col stylewidth: 17% / col stylewidth: 16% / col stylewidth: 15% / col stylewidth: 52% / /colgroup thead tr thHeader 1/ththHeader 2/ththHeader 3/ththHeader 4/th /tr /thead tbody tr tdbody row 1/tdtdcolumn 2/tdtdcolumn 3/tdtdcolumn 4/td /tr tr tdbody row 2/td td colspan2Cells may span columns./td tdfff/td /tr tr tdbody row 3/td td rowspan2Cells may span rows./td td rowspan2 ulliCells/lilican/lilicontain/liliblocks./li/ul /td td rowspan2 ul liThis is a very long line of text/li lia hrefhttp://www.python.org/Python/a/li lib/li lic/li /ul /td /tr trtdbody row 4/td/tr /tbody /table ^D对应的 AsciiDoc 输出[width100%,cols17%,16%,15%,52%,optionsheader,] | |Header 1 |Header 2 |Header 3 |Header 4 |body row 1 |column 2 |column 3 |column 4 |body row 2 2|Cells may span columns. |fff |body row 3 .2|Cells may span rows. .2a| * Cells * can * contain * blocks. .2a| * This is a very long line of text * http://www.python.org/[Python] * b * c |body row 4 |从这个输出可以提炼出 AsciiDoc 表格的核心语法也是 Pandoc 输出器的生成逻辑元素AsciiDoc 语法说明表格规范[width100%,cols17%,16%,15%,52%,optionsheader,]width取总百分比宽度cols按对齐符宽度%逐列生成options含header/footer表格边框|...|顶层表格的分隔符是|嵌套表格改用!单元格分隔|每个单元格以|开头跨列colspanNN例如2放在单元格内容之前源码中由colSpanFactor生成AsciiDoc.hs跨行rowspanN.N例如.2点号前缀源码中由rowSpanFactor生成AsciiDoc.hs块级单元格a|a表示该单元格内容按 AsciiDoc 渲染可容纳列表等块合并跨度组合2、.2、2.2等跨列数字在前、跨行点号数字在后中间用连接如源码spanFactor colSpanFactor rowSpanFactor所示AsciiDoc.hs注意跨列与跨行同时存在时的拼写2.2表示跨 2 列同时跨 2 行colspan 数字在前、rowspan 点号数字在后这在后面的案例五、案例六中会反复出现。宽度与对齐的生成规则表头[width100%,cols17%,16%,15%,52%,]中的百分比来自 HTML 的colgroup宽度由源码中的colspec与widths逻辑计算AsciiDoc.hs若各列宽度不全为 0先把宽度归一化为相对比例再映射为整数百分比并通过把余数加到第一列的方式保证百分比总和为 100见源码第 303-307 行每列规格colspec al wi由对齐运算符 百分比构成对齐运算符映射为AlignLeft→、AlignCenter→^、AlignRight→、AlignDefault→ 空AsciiDoc.hs若总宽度为 0未提供列宽信息则省略width项输出类似[cols,,,]。案例二多表头行与多表尾行的折叠策略AsciiDoc 只支持 1 个表头行和 1 个表尾行。测试的第二组场景演示了当 HTML 有2 个表头行 2 个表尾行时的行为。输入为两张表第一张是真值表表头两行、表体四行、表尾两行第二张是表头一行、表体一行、表尾一行的对照。输出为[cols,,,optionsheader,footer,] | 2|Inputs |Output |A |B |A or B |False |False |False |True |False |True |False |True |True |True |True |True |A |B |A or B 2|Inputs |Output | [cols,,optionsheader,footer,] | 2|Header |Body 1-1 |Body 2-1 2|Footer |关键点第二个表头行降级为表体首行表头第一行Inputs/A/B保留为 AsciiDoc 表头2|Inputs |Output表头第二行A/B/A or B变成表体第一行倒数第二个表尾行降级为表体末行表尾最后一行Inputs/Output保留为 AsciiDoc 表尾2|Inputs |Output表尾倒数第二行A/B/A or B变成表体最后一行由于表头/表尾都存在options变为header,footer折叠只是行的归属改变跨列合并2原样保留。这一折叠行为对应源码中两处逻辑adjustHeaders保留首行表头与adjustFooters保留末行表尾详见后文源码分析。案例三无表头但含表尾行的表格第三种场景HTML 表格没有thead只有tbody与tfoot表尾两行。输出[width100%,cols37%,37%,26%,optionsfooter,] | |False |False |False |True |False |True |False |True |True |True |True |True |A |B |A or B 2|Inputs |Output |要点由于没有表头行options中只有footer没有header表尾最后一行A/B/A or B成为 AsciiDoc 表尾倒数第二行2|Inputs |Output降级为表体最后一行列宽37%,37%,26%依然来自colgroup。options是否出现header/footer由源码中的optionSpecForRows决定AsciiDoc.hs只有当对应区域表头或表尾存在非空行时才输出该选项完全为空则省略。案例四多表头行的 rowspan 调整adjustHeaders 原理当表头本身包含跨行单元格时折叠会产生布局问题第一个表头行里rowspan跨越的高度有一部分会溢出到被降级的表体行中。第四组场景用四个 HTML 表格演示了 Pandoc 如何通过在第二行插入空单元格来保持布局。以第一个表格Location 跨 2 行、右侧温度表头跨 3 列为例输出为[width63%,cols49%,17%,17%,17%,optionsheader,] | |Location 3|Temperature 1961-1990 in degree Celsius | |min |mean |max |Antarctica |-89.2 |N/A |19.8 |Earth |-89.2 |14 |56.7 | [width63%,cols19%,17%,17%,47%,optionsheader,] | 3|Temperature 1961-1990 in degree Celsius |Location |min |mean |max | |-89.2 |N/A |19.8 |Antarctica |-89.2 |14 |56.7 |Earth | [width65%,cols20%,16%,16%,27%,21%,optionsheader,] | 3|Temperature 1961-1990 in degree Celsius |Location |Extra |min |mean |max | |Extra 2 |-89.2 |N/A |19.8 |Antarctica |Extra 3 |-89.2 |14 |56.7 |Earth |Extra 4 | [cols,,,optionsheader,] | |Header 1-1 2|Header 1-2 |Header 2-1 2| |Header 3-1 |Header 3-2 |Header 3-3 .2|Body 1-1 2|Body 1-2 |Body 2-1 |Body 2-2 | [cols,,,optionsheader,] | |Header 1-1 |Header 1-2 |Header 1-3 | |Header 2-1 | |Header 3-1 |Header 3-2 |Header 3-3 |观察关键细节第一个表格中Location原本rowspan2折叠后被改写为普通单元格其被吃掉的行高以空单元格|形式插入第二行| |min |mean |max保证后面表体行的列对齐不被破坏第二个表格方向相反Location在右列、rowspan2空单元格被插入第二行末尾|min |mean |max |第三个表格是更复杂的混合Location跨 2 行、Extra跨 1 行、第二行还有Extra 2输出第二行为|min |mean |max | |Extra 2——注意Location留下的空位在max之后第四个表格第 399 行附近展示了表头带2|跨列 跨行的组合输出第二行|Header 2-1 2|以空单元格补齐跨度第五个表格第 408 行附近中Header 1-2同时colspan2 rowspan2输出为|Header 1-1 |Header 1-2 |Header 1-3与第二行| |Header 2-1 |空单元格恰好落在跨行单元格的延续位置。这一行为对应源码中的adjustHeaders函数AsciiDoc.hs其算法如下只处理至少两行的表头对第一个表头行中的每个单元格若rowSpan 1把它改写为RowSpan 1跨行降级为单行同时生成一个空占位单元格其ColSpan与原单元格相同、RowSpan为rowSpan - 1即被削减掉的行高记录在原单元格的列位置把所有占位空单元格按列位置排序后用applyEmptyCells插入第二个表头行AsciiDoc.hs插入位置按当前列偏移精确对齐第一个表头行保留为 AsciiDoc 表头第二个及之后的行进入表体。案例五多表尾行的 rowspan 调整adjustFooters 原理表尾的折叠方向与表头相反最后一个表尾行保留为 AsciiDoc 表尾其余表尾行降级为表体底部。但当表尾行之间存在rowspan时这些跨度可能延伸到最后的表尾行同样需要在最后一行插入空单元格补偿。第五组场景用四个 HTML 表格覆盖了从 2 行到 6 行的各种表尾结构输出如下第一张表表体 1 行 表尾 4 行Footer 1-1/2跨 2 列、Span 3跨 3 行、Span 2跨 2 行[width100%,cols40%,40%,20%,optionsfooter,] | |Body 1-1 |Body 1-2 |Body 1-3 2|Footer 1-1/2 |Footer 1-3 |Footer 2-1 .2|Span 3 |Footer 2-3 |Span 2 |Footer 3-3 | | |Footer 4-3 |注意Span 3原本rowspan3且Footer 2-1下方还有Span 2rowspan2折叠后表尾只保留最后一行Footer 4-3而Span 3与Span 2的跨行延续以.2和空单元格末行| | |Footer 4-3中前两个|补齐。第二张表表体 2 行 表尾 6 行5 列跨度组合更复杂[cols,,,,,optionsfooter,] | |Body 1-1 |Body 1-2 |Body 1-3 |Body 1-4 |Body 1-5 |Body 2-1 |Body 2-2 |Body 2-3 |Body 2-4 |Body 2-5 3|Footer 1-1/2/3 |Footer 1-4 |Footer 1-5 |Footer 2-1 .3|Span 3 |Footer 2-3 2|Footer 2-4/5 .2|Span 2 2|Footer 3-3/4 .2|Span 2 .2|Span 3 |Footer 4-4 |Footer 5-1 |Footer 5-2 |Footer 5-4 |Span 2 2|Footer 6-1/2 | |Footer 6-4 | |这里可以看到多种跨度语法并存3|跨 3 列、.3|跨 3 行、.2跨 2 行、2|跨 2 列以及2|Footer 6-1/2 | |Footer 6-4 |中末尾的空单元格——这是为了补偿上方.2|Span 2与.3|Span 3的跨行延续。第三张表表尾 3 行Span 3同时colspan2 rowspan3[cols,,,,optionsfooter,] | |Body 1 |Body 2 |Body 3 |Body 4 |Footer 1-1 2.2|Span 3 .2|Span 2 |Footer 2-1 |Footer 3-1 2| |Footer 3-4 |2.2|Span 3是跨 2 列 跨 2 行的完整写法2 列在前、.2 行在后且由于行数不足其跨行高度被自动削减为 2.2并在末行以2|空单元格补齐列宽。第四张表表尾 6 行Span 6跨 6 行[cols,,,,optionsfooter,] | |Body 1-1 |Body 1-2 |Body 1-3 |Body 1-4 2|Footer 1-1/2 .5|Span 6 |Footer 1-4 .3|Span 3 |Footer 2-2 |Footer 2-4 |Footer 3-2 |Footer 3-4 |Footer 4-2 |Footer 4-4 |Footer 5-1 |Footer 5-2 |Span 2 2|Footer 6-1/2 | | |Span 6的rowspan6被削减为.5因为其所在行降级后只余 5 行可用高度末行相应位置留空。这些行为对应源码中的adjustFooters与adjustFooterCellAsciiDoc.hs其核心逻辑逐行扫描表尾区域adjustFooters用previousRowSpans这个Map记录来自上方行、尚未结束的 RowSpan及其列位置对每个单元格adjustFooterCell若它的rowIndex rowSpan footerLength即该跨行会延伸到最后一个表尾行则把它的 RowSpan 削减 1decrementRowSpanInCell并记录一个空占位单元格及其列位置所有占位空单元格被收集到columnIndices最后通过applyEmptyCells一次性插入最后一个表尾行若某单元格跨越的行数超过了剩余可用行数Pandoc 会按rowSpan - 1重新计算配合decrementTrailingRowSpans维护正确的列位置。案例六单元格级对齐native 输入与/^/运算符前面所有案例的输入都是 HTML第六组场景改用native 格式输入-f native直接以 Pandoc AST 文本描述一张表头 3 行、表体 2 行、表尾 4 行、且每个单元格都带有独立对齐和跨度的表格。native 输入的核心结构节选完整输入见 test/command/7326.md 第 605-758 行% pandoc -f native -t asciidoc [ Table ( , [] , [] ) (Caption Nothing []) [ ( AlignDefault , ColWidthDefault ) , ( AlignDefault , ColWidthDefault ) , ( AlignDefault , ColWidthDefault ) ] (TableHead ( , [] , [] ) [ Row ( , [] , [] ) [ Cell ( , [] , [] ) AlignLeft (RowSpan 1) (ColSpan 1) [ Plain [ Str Left , Space , Str Header ] ] , Cell ( , [] , [] ) AlignCenter (RowSpan 2) (ColSpan 2) [ Plain [ Str Center , Space , Str Headers ] ] ] ... ]) ... ] ^D期望输出[cols,,,optionsheader,footer,] | |Left Header 2^|Center Headers |Right Header 2| ^|Center Header |Right Header |Left Header .2|Right Body 2|Left Body ^|Center Body |Right Body 3^|Center Footer 2|Left Footer .2^|Center Footer 2|Right Footer 2^|Center Footer | |这段输出是单元格级对齐 跨度的语法大全对齐运算符置于单元格分隔符之前|Left Header左对齐、|Right Header右对齐、^|Center Header居中对齐与跨度叠加2^|Center Headers表示跨 2 列且居中.2|Right Body表示跨 2 行且右对齐2|Left Body表示跨 2 列且左对齐同时跨行列2^|Center Footer跨 2 列居中、.2^|Center Footer跨 2 行居中等跨行延续处以空单元格补位表尾第二行2|Right Footer之后末行以2^|Center Footer |中的空|补齐Left Footer的跨列延续。这一输出完全由源码中的makeCellWithSpansAndAlignment生成AsciiDoc.hs先计算spanFactor colSpanFactor rowSpanFactor再在前面拼上alignmentOperator alignment最后若跨度非空则用连接spanFactor alignedCell。对齐运算符与宽度的映射见 AsciiDoc.hs。案例七空行的 rowspan 调整adjustEmptyRows 原理最后一个场景也是 7326.md 篇幅最大的部分第 760-1227 行专门处理空行AST 中存在Row ( , [] , [] ) []无任何单元格的行。AsciiDoc 无法表达这种空行因此 Pandoc 的策略是空行不输出但它占据的行高会被消费——所有跨越它的 RowSpan 各自减 1从而保证后续行的列对齐正确。第一个 native 表格表头 3 行含 1 个空行、表体 6 行含 2 个空行、表尾 5 行含 1 个空行的输出[cols,,,optionsheader,footer,] | |Header 1-1 |Span 3 |Header 1-3 |Header 2-1 | |Header 2-3 2|Body 1-1/2 .3|Span 5 |Body 2-1 |Body 2-2 |Body 3-1 |Body 3-2 | | | .3|Span 5 2|Footer 1-2 2|Span 2 2|Footer 3-2/3 | 2|Footer 4-2/3 |对照输入可以验证表头部分原RowSpan 3的Span 3因为中间夹了一个空行且表头只保留首行输出中Span 3与空行被压缩为表体第一行的.3|Span 5形式的空位补偿表头第二行输出为|Header 2-1 | |Header 2-3中间|即Span 3的延续空位表体部分Body 1-1/2跨 3 行、Span 5跨 5 行两个空行被吞并后Span 5变为.35 - 2 个空行表体底部出现| | |空行补齐表尾部分Span 5表尾首行跨 5 行但因 1 个空行被消费变为.3。第二个 native 表格无表头、表体 7 行含 2 个空行、表尾 8 行含 2 个空行的输出[cols,,,optionsfooter,] | |Body 1-1 |Body 1-2 .2|Span 4 .3|Span 5 |Body 2-2 |Body 3-2 |Body 3-3 |Body 4-2 |Body 4-3 | | | |Body 6-1 |Body 6-2 |Span 6-3 |Footer 1-1 .5|Span 8 |Footer 1-3 .2|Span 3 |Footer 2-3 |Span 2 |Footer 4-1 |Footer 4-3 |Footer 5-1 |Span 3 |Span 2 | | |第三个 native 表格无表头、表体 8 行含 2 个空行、无表尾的输出[cols,,,] | .5|Span 6 |Body 1-2 .2|Span 2 .2|Span 3 .3|Span 4 |Body 3-2 |Body 4-2 | | | | | | |这里Span 6的RowSpan 6因 2 个空行被消费变为.56 行中减去自己所在行再减去 2 个空行Span 4同理变为.3表尾空行则直接不输出TableFoot ( , [] , [] ) []对应无footer选项。这套逻辑对应源码中的adjustEmptyRowsAsciiDoc.hs算法要点为每个rowSpan 1的单元格初始化rowsLeft rowSpan - 1减掉自身所在行扫描后续行若遇到完全无单元格的行且当前存在rowsLeft 1的跨行单元格则消费该空行——所有相关单元格rowsLeft - 1、RowSpan 同步decrementRowSpanInCellAsciiDoc.hs并丢弃该空行若空行之后没有可消费的跨行则该空行被原样保留例如第三个表格底部的| | |空行处理完的 RowSpan 数值直接决定输出的.N前缀。从源码结构看adjustEmptyRows对表头、表体、表尾三个区域分别调用AsciiDoc.hs并在折叠表头/表尾之前执行因此跨行高度的削减会与adjustHeaders/adjustFooters的占位逻辑叠加生效。源码级总结一张复杂表格的完整生成流程综合 src/Text/Pandoc/Writers/AsciiDoc.hs 中blockToAsciiDoc对Table的处理第 286-400 行一张复杂表格的输出由以下步骤串成读取旧式表格视图通过toLegacyTable提取 caption、对齐、列宽、表头/表体/表尾第 287-291 行空行调整对表头、表体、表尾分别执行adjustEmptyRows吞并空行并削减 RowSpan第 289-291 行表头折叠adjustHeaders保留首行表头、把其余表头行降级为表体、用空单元格补偿跨行第 379-381 行表尾折叠adjustFooters保留末行表尾、把其余表尾行降级为表体、用空单元格补偿跨行第 380-382 行生成表规范[width...,cols...,options...,]——宽度来自列宽总和cols逐列拼对齐符百分比options按表头/表尾是否有非空行决定是否含header/footer第 296-334 行生成单元格makeCell处理普通/多块单元格a|前缀、makeCellWithSpansAndAlignment叠加对齐与N/.N跨度前缀第 346-376 行嵌套表格支持顶层分隔符为|嵌套一层内为!超过一层嵌套会输出BlockNotRendered警告并跳过第 342-357 行自动换行根据--wrap设置决定是否按列宽折行第 393-397 行。此外若单元格内出现 AsciiDoc 无法表达的内容如脚注、多段落块无法在普通单元格呈现Pandoc 会通过日志机制报告省略信息模块头注释第 15-19 行与此相关的单元测试可见 test/Tests/Writers/AsciiDoc.hs 的 tables 测试组empty cells 与 multiblock cells 两个用例第 79-100 行。实操验证与扩展如果你希望在自己的环境里复现 7326.md 的全部行为可以直接运行命令测试# 在仓库根目录下构建测试程序 make quicktest # 或按 INSTALL.md 指引构建 test-pandoc # 单独运行 7326 号测试 cabal test pandoc --test-options--pattern 7326也可以脱离测试框架手动验证例如把 test/command/7326.md 中任意一个% pandoc ...代码块的内容含^D之前的部分复制到终端pandoc -f html -t asciidoc EOF table trthHeader 1/ththHeader 2/th/tr trtdbody row 1/tdtdcolumn 2/td/tr /table EOF注意输出器同时提供asciidoc现代 AsciiDoc/Asciidoctor 语义与asciidoc_legacyasciidoc-py语义两种格式MANUAL.txt 第 305-306 行7326.md 针对的是asciidoc输出器若你的下游工具链使用旧版 Python 实现应改用-t asciidoc_legacy并注意两者在引号、任务列表等语法上的差异。小结通过 test/command/7326.md 这组回归测试可以系统掌握 Pandoc 输出 AsciiDoc 表格时的全部关键规则跨度语法N跨列、.N跨行、2.2同时跨行列、a|块级单元格对齐语法/^/运算符位于|之前可与跨度叠加表头/表尾折叠只保留第一个表头行与最后一个表尾行其余降级为表体跨行延续用空单元格补齐空行吞并空行不输出其行高被所有跨越它的 RowSpan 消费RowSpan 减 1底层支撑adjustHeaders、adjustFooters、adjustEmptyRows、makeCellWithSpansAndAlignment等函数协同完成从 Pandoc AST 到 AsciiDoc 的无损布局映射。理解了这套规则与源码实现你在处理HTML 表格转 AsciiDoc 后布局错乱一类问题时就能快速定位是跨行高度、空行还是多表头折叠导致的问题并据此调整源表格结构。赞分享文档开发工具CLI【免费下载链接】pandocUniversal markup converter项目地址https://gitcode.com/gh_mirrors/pa/pandoc点击查看免费下载相关推荐Pandoc 网格表 rowspan/colspan 转换实战HTML 表格到 Markdown 网格表的完整解析Pandoc 网格表 rowspan/colspan 转换实战HTML 表格到 Markdown 网格表的完整解析 导读 本文围绕 Pandoc 仓库中针对复文档开发工具CLIantd Table 单元格与表头合并实战colSpan / rowSpan 用法全解析antd Table 单元格与表头合并实战colSpan / rowSpan 用法全解析 导读本文以 Ant DesignantdTable 组件官方的前端UI组件设计系统pandoc 中 MediaWiki 表格到 HTML 的转换rowspan/colspan 合并单元格的完整解析链路pandoc 中 MediaWiki 表格到 HTML 的转换rowspan/colspan 合并单元格的完整解析链路 本文以 pandoc 仓库中的命令测试文档开发工具CLI上一篇Real-ESRGAN图像增强3步掌握AI超分辨率魔法下一篇如何快速上手Kimi-K2.5-W4A85步完成AMD硬件上的模型部署创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考