将值写入文件

将值写入文件

我想将宏的内容写入外部文件。以下代码

\documentclass{article}
\begin{document}
\newcommand\foo[3]{1: #1, 2: #2 and 3: #3}

\foo{foo}{bar}{baz}

\foo{See \ref{sec}}{\begin{description}
  \item[whatever] Hello
\end{description}}{Some text}

\section{A section}
\label{sec}

\end{document}

写入PDF 文件。这应该转到外部文件,可能是 XML 或 CSV 或其他可解析的文件。我只需要宏的输出1: foo, 2: bar and 3: baz1: See 1, 2: whatever Hello and 3: Some text可以忽略换行符),而不是源(\ref{...}例如)

我使用 LuaLaTeX,因此我可能直接解析输出节点,但在宏观层面可能存在解决方案?

答案1

从评论来看,您已经知道这一点,但您可以使用类似以下内容打开文件

\newwrite\myoutput
\immediate\openout\myoutput=\jobname.output

我使用 tex 文件名\jobname作为输出文件,并添加“output”扩展名。您可以使用以下方式写入此文件

\write\myoutput{stuff}

使用 MWE 时,扩展会出现严重错误。为了解决这个问题,我过去曾使用过\unexpandedwrite在 TeXbook 某处找到的一个宏。使用它,我可以让 MWE 编译并生成输出:

1: foo
2: bar
 and 3: baz
1: See 1\hbox {}
2: \begin {description} \item [whatever] Hello \end {description}
 and 3: Some text

根据您对#1#2和的期望,#3您当然可以\write将 用作其中一些,也可以\unexpandedwrite将其用作其他。下面是我所做的。

编辑

@jfbu 在评论中指出现在有一个\unexpanded宏,所以\unexpandedwrite不再需要,因此我的 MWe 可以缩短为:

\documentclass{article}

\newwrite\myoutput
\immediate\openout\myoutput=\jobname.output

\newcommand\foo[3]{%
  \write\myoutput{1: #1}
  \write\myoutput{\unexpanded{2: #2}}
  \write\myoutput{ and 3: #3}
}

\begin{document}
  \foo{foo}{bar}{baz}

  \foo{See \ref{sec}}{\begin{description}
    \item[whatever] Hello
  \end{description}}{Some text}

  \section{A section}
  \label{sec}

  \immediate\closeout\myoutput  % to close the file
\end{document}

原始代码如下:

\documentclass{article}

%% from the TeXbook
\def\\{\let\stoken= } \\
\long\def\unexpandedwrite#1#2{\def\finwrite{\write#1}%
  {\aftergroup\finwrite\aftergroup{\sanitize#2\endsanity}%
  }}
\def\sanitize{\futurelet\next\sanswitch}
\def\sanswitch{\ifx\next\endsanity
  \else\ifcat\noexpand\next\stoken\aftergroup\space\let\next=\eat
  \else\ifcat\noexpand\next\bgroup\aftergroup{\let\next=\eat
  \else\ifcat\noexpand\next\egroup\aftergroup}\let\next=\eat
  \else\let\next=\copytoken\fi\fi\fi\fi \next
}
\def\eat{\afterassignment\sanitize \let\next= }
\long\def\copytoken#1{%
  \ifcat\noexpand#1\relax\aftergroup\noexpand
  \else\ifcat\noexpand#1\noexpand~\aftergroup\noexpand\fi\fi
  \aftergroup#1\sanitize%
}
\def\endsanity\endsanity{}

\newwrite\myoutput
\immediate\openout\myoutput=\jobname.output

\newcommand\foo[3]{%
  \write\myoutput{1: #1}
  \unexpandedwrite\myoutput{2: #2}
  \write\myoutput{ and 3: #3}
}

\begin{document}
  \foo{foo}{bar}{baz}

  \foo{See \ref{sec}}{\begin{description}
    \item[whatever] Hello
  \end{description}}{Some text}

  \section{A section}
  \label{sec}
\end{document}

答案2

快速概念证明:

\documentclass{article}
\usepackage{atbegshi}
\AtBeginShipout{\directlua{analyzebox(tex.box["AtBeginShipoutBox"])}}
\directlua{dofile("foo.lua")}

\begin{document}
\newcommand\foo[3]{1: \directlua{starttoken(1)}#1\directlua{stoptoken(1)},%
                   2: \directlua{starttoken(2)}#2\directlua{stoptoken(2)}%
               and 3: \directlua{starttoken(3)}#3\directlua{stoptoken(3)}}

\foo{foo}{bar}{baz}

\foo{See \ref{sec}}{\begin{description}
  \item[whatever] Hellö
\end{description}}{Some text}

\section{A section}
\label{sec}

\end{document}

并且foo.lua

function starttoken(n)
    local ud = node.new("whatsit","user_defined")
    ud.user_id = 41564
    ud.type = 100
    ud.value = n  * 2
    node.write(ud)
end

function stoptoken(n)
    local ud = node.new("whatsit","user_defined")
    ud.user_id = 41564
    ud.type = 100
    ud.value = n * 2 + 1
    node.write(ud)
end

local hlist = node.id("hlist")
local vlist = node.id("vlist")
local glyph = node.id("glyph")
local glue = node.id("glue")
local whatsit = node.id("whatsit")
local user_defined
for k,v in pairs(node.whatsits()) do
    if v == "user_defined" then
        user_defined = k
    end
end

local inlist = false
local charlist = {}
local charlists = {}

function analyzebox( box )
    while box do
        if box.id == hlist or box.id == vlist then
            analyzebox(box.list)
        elseif box.id == glyph and inlist then
            charlist[#charlist + 1] = unicode.utf8.char(box.char)
        elseif inlist and box.id == glue and #charlist > 0 and charlist[#charlist] ~= " " then
            charlist[#charlist + 1] = " "
        elseif box.id == whatsit and box.subtype == user_defined and box.user_id == 41564 then
            local curlist
            local val = box.value
            if val % 2 == 0 then
                inlist = true
            else
                inlist = false
                curlist = (val - 1) / 2
                if charlist[#charlist] == " " then
                    table.remove(charlist)
                end
                if curlist < 3 then
                    charlists[curlist] = charlist
                else
                    texio.write_nl(string.format("%q, %q, %q",table.concat(charlists[1],""),table.concat(charlists[2],""),table.concat(charlist,"")))
                    charlists = {}
                end
                charlist = {}
            end
        end
        box = box.next
    end
end

写道

"foo", "bar", "baz"
"See 1", "whatever Hellö", "Some text"

到输出...

相关内容