Pandoc LaTeX 读取器对 siunitx 负数的处理:`\SI` 命令正负号转换的源码解析与命令测试验证

发布时间:2026/9/21 16:14:33
Pandoc LaTeX 读取器对 siunitx 负数的处理:`\SI` 命令正负号转换的源码解析与命令测试验证 文档开发工具CLI【免费下载链接】pandocUniversal markup converter项目地址https://gitcode.com/gh_mirrors/pa/pandoc点击查看免费下载本文基于 pandoc 仓库中的命令测试用例 test/command/6844.md深入剖析 pandoc 的 LaTeX 读取器Reader对 siunitx 宏包\SI命令中正数、负数与带符号数字的处理方式负号会被转换为 Unicode 减号 U2212−正号则会被静默丢弃数字与单位之间以不间断空格NBSP连接。读完本文你将掌握\SI以及同族的\num、\SIrange、\SIlist、\ang等在 pandoc 中的完整解析链路与正负号转换规则并能直接在本地复现验证。一、背景siunitx 宏包与 pandoc 的内置支持siunitx 是 LaTeX 生态中最常用的国际单位制SI排版宏包提供\SI{数值}{单位}、\num{数值}、\si{单位}、\SIrange{起}{止}{单位}等命令负责科学论文中的数值与单位排版如\SI{123}{\celsius}表示 123 摄氏度。pandoc 的 LaTeX 读取器对 siunitx 提供了原生支持无需加载任何额外 Lua 过滤器在 src/Text/Pandoc/Readers/LaTeX.hs 中inlineCommands通过M.unions将siunitxCommands tok合并进所有行内命令表而siunitxCommands本身定义在独立的模块 src/Text/Pandoc/Readers/LaTeX/SIunitx.hs 中。该模块注册的命令映射如下见 SIunitx.hs命令对应处理器说明\si、\unitdosi仅解析单位\unit为 siunitx v3 的\si\SI、\qtydoSI数值 单位\qty为 v3 版本\SIrange、\qtyrangedoSIrange True数值区间 单位\SIlist、\qtylistdoSIlist数值列表 单位\numrangedoSIrange False纯数值区间无单位\numlistdoSInumlist纯数值列表\numdoSInum纯数值\angdoSIang角度度/分/秒测试文件 test/command/6844.md 正是针对其中使用频率最高的\SI命令验证其**负数negative numbers**的解析行为。二、核心测试用例正数、负数与正号的三种处理结果6844.md通过三个命令测试用例Command Test用-t native输出 Pandoc 原生 AST完整记录了对\SI传入不同符号数值时的行为。以下是原文的全部用例用例一正数% pandoc -f latex -t native \SI{123}{\celsius} ^D [ Para [ Str 123\160\176C ] ]用例二负数% pandoc -f latex -t native \SI{-123}{\celsius} ^D [ Para [ Str \8722\123\160\176C ] ]用例三显式正号% pandoc -f latex -t native \SI{123}{\celsius} ^D [ Para [ Str 123\160\176C ] ]2.1 如何读懂 native 输出中的数字转义这三个用例的输出都是单个Str行内元素其中出现了几类 Haskell 十进制转义序列需要正确解读这些转义是 pandoc native writer 对非 ASCII 字符的show表示并非最终输出文本的一部分\160十进制 1600xA0即不间断空格 NBSP。它正是 siunitx 排版中数值与单位之间的标准间距\176十进制 1760xB0即度数符号°来自\celsius单位\8722十进制 87220x2212即 Unicode减号 −U2212 MINUS SIGN注意它不同于 ASCII 的连字符减号-U002D\这是 Haskellshow为终止数字转义序列插入的空转义符避免\8722\123被误读为码点 87221。它只存在于 native 表示层不产生任何实际字符。因此三个用例的真实转换结果分别为输入 LaTeX转换后的实际文本行为说明\SI{123}{\celsius}123 °CNBSP 连接正常正数原样保留\SI{-123}{\celsius}−123 °CU2212 减号ASCII-被替换为 Unicode 减号 −\SI{123}{\celsius}123 °C显式正号被静默丢弃这与 siunitx 在 LaTeX 中的排版惯例一致科学排版中负数应使用真正的减号 −而非连字符而正号默认不显示。三、源码级解析正负号究竟是如何被转换的要理解上述行为需要追踪\SI的完整解析链路。在 SIunitx.hs 中doSI依次完成三件事解析数值、解析可选的前缀符号如货币\$、解析单位doSI tok do skipopts value - doSInum valueprefix - option $ bracketed tok unit - dosi tok return . mconcat $ [valueprefix, emptyOr160 valueprefix, value, emptyOr160 unit, unit] doSInum :: PandocMonad m LP m Inlines doSInum skipopts * (tonum . untokenize $ braced) tonum :: Text - Inlines tonum value case runParser parseNum () value of Left _ - text value Right num - num数值参数{...}花括号内容被untokenize还原为纯文本后交给parseNum解析解析失败时则原样回退为普通文本保证了对非常规写法的宽容性。parseNum由parseNumPart组成而正负号的处理逻辑集中在其中的parseDecimalNum见 SIunitx.hsparseDecimalNum try $ do pref - option mempty $ (mempty $ char ) | (minus $ char -) basenum - many1 (satisfy (\c - isDigit c || c .)) ...其中minus的定义为SIunitx.hsminus :: Text minus \x2212这两行代码就是全部答案遇到字符时前缀被解析为mempty空——正号被直接丢弃这正是\SI{123}{\celsius}输出123 °C的原因遇到字符-时前缀被替换为\x2212Unicode 减号 −——这就是\SI{-123}{\celsius}输出−123而非 ASCII-123的原因两者都没有匹配时前缀为空数值保持原样。从源码结构还可以推断出该解析器的一个健壮性细节当小数部分以.开头时如.3e45会自动补前导0得到0.3这一点在 test/command/6658.md 的\num{.3e45}用例中也有印证输出0.3 × 10⁴⁵。四、数字解析器的完整能力不只是正负号parseNumPart采用多分支选择结构SIunitx.hs除了前文的正负号还支持一整套科学记数法语法理解它有助于解释\SI在更多输入下的行为分支触发输入转换结果parseDecimalNum数字、小数点前导/-保留数字-→ −U2212parseComma千位分隔逗号,转为.如12345,67890→12345.67890parsePlusMinus-±NBSP ± NBSPU00B1parsePM\pm±同上parseParens(...)括号内数字不确定度uncertainty自动对齐小数位parseIi虚数单位i如1-2i→1 ± 2iparseXx×乘号 U00D7parseExpe 数字× 10上标形式如.3e45→0.3 × 10⁴⁵其中不确定度的对齐算法值得注意\SI{12.3(60)}{\m}会输出12.3 ± 6 m而\SI{0.135(21)}{\m}会输出0.135 ± 0.021 m——即根据小数点后位数自动补齐不确定度的有效位相关验证见 test/command/6620.md。五、负号处理在其他 siunitx 命令中的体现hyphenToMinusSIunitx.hs是模块内另一处负号转换它把字符串中的-批量替换为减号 −U2212用于\raisetothe、\tothe、^上标、_下标等指数/角标场景保证\SI{2}{\metre\tothe{-2}}这类写法输出的是真正的减号上标。角度命令\ang则体现了另一侧的符号处理SIunitx.hs通过dropPlus将度/分/秒各段前的显式正号去掉同时保留负号。例如 test/command/6658.md 中\ang{10;;}→10°正号被丢弃\ang{-0;1;}→-0°1′负号保留综合来看pandoc 对 siunitx 符号的处理遵循一条统一约定正号仅作显式声明、不进入输出负号统一规范化为 Unicode 减号 −这与科学出版排版规范保持一致。六、如何本地复现验证命令测试采用 pandoc 的标准 golden-test 格式% pandoc 参数声明命令^D之后的缩进行为期望输出。你可以直接在终端复现这三个用例# 负数注意输出中的 \8722U2212 减号 printf \\SI{-123}{\\celsius}\n | pandoc -f latex -t native # 正数NBSP\160 度\176 C printf \\SI{123}{\\celsius}\n | pandoc -f latex -t native # 显式正号 被丢弃与正数结果一致 printf \\SI{123}{\\celsius}\n | pandoc -f latex -t native若改用-t html或 markdown 等实际输出格式你将看到更直观的结果负数输出为带 U2212 减号的−123 °C正号输入则输出123 °C。pandoc 的命令测试框架Tests.Command入口见 test/test-pandoc.hs会逐条比对6844.md这类文件中的输入与期望 AST确保该行为在后续版本中不会回归。七、相关源码与测试导航如果你希望进一步深入以下路径覆盖了 siunitx 支持的全貌实现主体src/Text/Pandoc/Readers/LaTeX/SIunitx.hs命令注册表、数字/单位解析器、前缀/后缀修饰符、单位与词头映射表命令挂载点src/Text/Pandoc/Readers/LaTeX.hssiunitxCommands并入inlineCommands相关命令测试test/command/3587.md\SI/\SIrange的单位、前缀符号、平方/立方与round-precision选项、test/command/6620.md不确定度与\pm、test/command/6658.md\num/\si/\ang/列表与区间命令本主题用例test/command/6844.md正数、负数与显式正号的行为基线。综上pandoc 对 siunitx 负数的处理可归纳为一条简洁而明确的规则-规范化为一等公民的 Unicode 减号 −U2212视为冗余声明予以剥离数值与单位间以不间断空格衔接。这一行为既有 6844.md 的黄金测试锁定也有 SIunitx.hs 中parseDecimalNum的两行代码直接支撑是 LaTeX 科学文档迁移到 Pandoc 生态时可以放心依赖的能力。赞分享文档开发工具CLI【免费下载链接】pandocUniversal markup converter项目地址https://gitcode.com/gh_mirrors/pa/pandoc点击查看免费下载相关推荐Pandoc LaTeX 阅读器解析 siunitx \SI 与 \SIrange 命令命令测试到源码实现的完整解读Pandoc LaTeX 阅读器解析 siunitx \SI 与 \SIrange 命令命令测试到源码实现的完整解读 本篇技术指南以 pandoc 仓库中的命文档开发工具CLIPandoc DokuWiki 读取器中的花括号{/{{转义处理命令测试 5416 源码级解析Pandoc DokuWiki 读取器中的花括号 { / {{ 转义处理命令测试 5416 源码级解析 导读 DokuWiki 使用 {{...}} 双花文档开发工具CLIeDBG编译指南在macOS和Linux上交叉编译Android ARM64调试器eDBG编译指南在macOS和Linux上交叉编译Android ARM64调试器 eDBG是一款基于eBPF的轻量级Android调试器支持MCP功能本文档开发工具CLI创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考