You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写Lua版Pandoc过滤器 为非标题文本添加术语鼠标悬停提示

问题解决方案

一、报错问题根因与修复

你的代码报错是三个低级错误共同导致的:

  • 变量名不匹配:Str回调的入参名是el,但代码里写的是elem.text,取值失败导致返回nil
  • 返回值类型错误:Pandoc级过滤器必须返回完整的pandoc.Pandoc文档对象,原代码遍历到第一个非Header块就直接返回单块处理结果,既丢失了剩余内容,返回值类型也不符合要求
  • 遍历逻辑错误:原代码没有将修改后的块写回文档的blocks数组,修改没有生效

二、带标点术语匹配问题修复

原有逻辑是判断整个Str节点的文本完全等于术语key才替换,自然无法匹配CO,/SBP;这类附带标点的场景。需要改用正则拆分Str节点内容,提取所有独立存在的术语,将术语部分替换为带提示的Span,其余文本保留为普通Str节点即可。

完整可运行代码

-- 术语表定义
local glossary = {CO = "Cardiac Output", DBP = "Diastolic Blood Pressure", SBP = "Systolic Blood Pressure"}

-- 预编译带单词边界的术语匹配正则,避免误匹配长单词中的片段
local pattern = '%f[%w](' .. table.concat(pandoc.utils.keys(glossary), '|') .. ')%f[%W]'

function Pandoc(doc)
  -- 遍历所有块,仅处理非Header块
  for i, block in ipairs(doc.blocks) do
    if block.t ~= 'Header' then
      -- 将修改后的块写回文档
      doc.blocks[i] = pandoc.walk_block(block, {
        Str = function(el)
          local res = {}
          local last_end = 1
          -- 遍历当前Str中所有匹配到的术语
          for start, match, end_pos in el.text:gmatch('()' .. pattern .. '()') do
            -- 插入术语前的剩余文本
            if start > last_end then
              table.insert(res, pandoc.Str(el.text:sub(last_end, start - 1)))
            end
            -- 插入带提示的术语Span
            table.insert(res, pandoc.Span(match, {
              title = glossary[match],
              class = 'glossary'
            }))
            last_end = end_pos
          end
          -- 插入最后一个术语之后的剩余文本
          if last_end <= #el.text then
            table.insert(res, pandoc.Str(el.text:sub(last_end)))
          end
          -- 无匹配时返回nil保留原节点,有匹配时返回替换后的节点列表
          return #res > 0 and res or nil
        end
      })
    end
  end
  -- 返回修改后的完整文档对象
  return doc
end

上述代码完全符合你的需求:标题中的术语不会被处理,正文里无论术语是单独出现、紧跟标点、还是在列表中都会被正确识别替换。

内容的提问来源于stack exchange,提问作者cjdbarlow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 11:12:03