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

Pandoc与LaTeX:导入公式标签时Lua过滤器报错求助

问题

已知pandoc-eqnos过滤器无法正常工作且处于半废弃状态,因此编写Lua过滤器实现以下目标:提取LaTeX中的equation环境,生成仅包含公式及对应标签的独立文件,将公式转为图片后导入最终docx文件。运行时出现报错:

Error running filter filter.lua:
Inline, list of Inlines, or string expected, got table

最小工作示例(MWE)

.tex文件代码

\documentclass{article}
\usepackage{amsmath}
\usepackage{mathtools}
\usepackage{blindtext}
\usepackage{tikz}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\usepackage{siunitx}
\usepackage{graphicx}
\usepackage{stix2}
\usepackage{microtype}
\usepackage{pifont}
\title{Sections and Chapters}
\author{Overleaf}
\date{\today}

\begin{document}
\maketitle
\tableofcontents
\section{Introduction}

This is the first section.

\begin{equation}
    \underset{\mathrm{Einstein}}{E} = mc^2
\end{equation}

Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Etiam lobortis 
facilisis sem. Nullam nec mi et neque pharetra sollicitudin. Praesent imperdiet
mi nec ante. Donec ullamcorper, felis non sodales commodo, lectus velit ultrices
augue, a dignissim nibh lectus placerat pede.
Vivamus nunc nunc, molestie
ut, ultricies vel, semper in, velit.
Ut porttitor.
Praesent in sapien.
Lorem
ipsum dolor sit amet, consectetuer adipiscing elit. Duis fringilla tristique neque.
Sed interdum libero ut metus.
Pellentesque placerat.
Nam rutrum augue a
leo. Morbi sed elit sit amet ante lobortis sollicitudin. Praesent blandit blandit
mauris.
Praesent lectus tellus, aliquet aliquam, luctus a, egestas a, turpis.
Mauris lacinia lorem sit amet ipsum. Nunc quis urna dictum turpis accumsan
semper.

\end{document}

Lua过滤器代码

local file = "C:/Logs/test.tex"

function all_trim(s)
    return s:match("^%s*(.-)%s*$")
end

function file_exists(name)
    local f = io.open(name, "r")
    if f ~= nil then
        io.close(f)
        return true
    else
        return false
    end
end

function get_line(filename, line_number)
    local i = 0
    for line in io.lines(filename) do
        i = i + 1
        if i == line_number then
            return line
        end
    end
    return nil -- line not found
end

function lines_from(file)
    if not file_exists(file) then
        return {}
    end
    local lines = {}
    for line in io.lines(file) do
        lines[#lines + 1] = line
    end
    return lines
end

-- tests the functions above

local lines = lines_from(file)

local section,equation = 0, 0


for k, v in pairs(lines) do
    if string.find(v, "\\section") then
        figure = 0
        section = section + 1
    end
    if string.find(v, "\\begin{equation}") then
        equation = equation + 1
    end
end


function Math(el)
    if (el.mathtype == "DisplayMath") then
        counter = counter + 1
        io.output("C:/Logs/output.tex")
        io.write("\\documentclass[preview]{standalone}", "\n")
        local i = 2
        for k, v in pairs(lines) do
            while not string.find(lines[i], "\\begin{document}") do
                io.write(lines[i], "\n") -- write preamble
                i = i + 1
            end
        end
        io.write("\\begin{document}", "\n")
        io.write("\\begin{equation}", "\n")
        io.write(el.text, "\n")
        io.write("\\label{"..section.."."..equation.."}", "\n")
        io.write("\\end{equation}", "\n")
        io.write("\\end{document}", "\n")
        io.close()
        os.execute("cd C:/Logs & pdflatex output.tex & convert -density 288 output.pdf -alpha off output.png")
        return { pandoc.Para({pandoc.Image({},"C:/Logs/output.png")})}
    end
end

执行命令

pandoc --from latex+raw_tex --filter pandoc-eqnos --lua-filter=filter.lua -s test.tex -o test.docx

错误信息

Error running filter filter.lua:
Inline, list of Inlines, or string expected, got table
解决方案

错误原因

报错的直接原因是pandoc.Image构造参数不合法:pandoc.Image({},"C:/Logs/output.png")中第一个参数是空表,但Image要求第一个参数为Inline元素列表、单个Inline元素或字符串,空表不符合要求。

除此之外,原过滤器还有其他潜在问题:

  • counter变量未初始化,会触发运行时错误;
  • 导言区写入逻辑重复遍历原文件,导致代码冗余且可能重复写入内容;
  • 全局计数变量section和equation无法对应当前处理的公式,会导致所有公式使用相同标签。

修复步骤

  1. 给pandoc.Image添加合法的替代文本,将空表替换为公式文本对应的Inline元素;
  2. 初始化counter等计数变量;
  3. 预提取原文件的导言区,避免重复遍历;
  4. 调整计数逻辑,确保每个公式对应正确的章节和公式编号。

修改后的Lua过滤器代码

local input_file = "C:/Logs/test.tex"
local output_dir = "C:/Logs/"

function all_trim(s)
    return s:match("^%s*(.-)%s*$")
end

function file_exists(name)
    local f = io.open(name, "r")
    if f ~= nil then
        io.close(f)
        return true
    else
        return false
    end
end

function lines_from(file)
    if not file_exists(file) then
        return {}
    end
    local lines = {}
    for line in io.lines(file) do
        lines[#lines + 1] = line
    end
    return lines
end

-- 预加载原文件并提取导言区
local all_lines = lines_from(input_file)
local preamble = {}
local in_preamble = true

for _, line in ipairs(all_lines) do
    if in_preamble then
        table.insert(preamble, line)
        if string.find(line, "\\begin{document}") then
            in_preamble = false
        end
    else
        break
    end
end

-- 初始化计数器
local current_section = 0
local equation_counter = 0
local global_counter = 0

-- 预统计章节数量
for _, line in ipairs(all_lines) do
    if string.find(line, "\\section") then
        current_section = current_section + 1
    end
end

function Math(el)
    if el.mathtype == "DisplayMath" then
        global_counter = global_counter + 1
        equation_counter = equation_counter + 1
        -- 生成唯一文件名,避免覆盖
        local tex_filename = output_dir .. "output_" .. global_counter .. ".tex"
        local pdf_filename = output_dir .. "output_" .. global_counter .. ".pdf"
        local png_filename = output_dir .. "output_" .. global_counter .. ".png"

        -- 写入独立TeX文件
        local f = io.open(tex_filename, "w")
        f:write("\\documentclass[preview]{standalone}\n")
        -- 跳过原documentclass行,写入剩余导言区
        for i = 2, #preamble do
            f:write(preamble[i] .. "\n")
        end
        f:write("\\begin{document}\n")
        f:write("\\begin{equation}\n")
        f:write(el.text .. "\n")
        f:write("\\label{" .. current_section .. "." .. equation_counter .. "}\n")
        f:write("\\end{equation}\n")
        f:write("\\end{document}\n")
        f:close()

        -- 编译并转换为图片,添加nonstopmode避免中断
        os.execute("cd " .. output_dir .. " & pdflatex -interaction=nonstopmode " .. tex_filename)
        os.execute("convert -density 288 " .. pdf_filename .. " -alpha off " .. png_filename)

        -- 返回合法的Image元素,用公式文本作为替代文本
        return pandoc.Para({
            pandoc.Image({pandoc.Str(el.text)}, png_filename)
        })
    end
end

执行说明

修改后执行原命令即可,生成的每个公式会对应独立的output_*.tex、output_*.pdf和output_*.png文件,避免文件覆盖,同时公式标签能正确关联章节编号。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 21:25:59