使用 Plain TeX 逐字写入

使用 Plain TeX 逐字写入

我正在尝试将逐字文本写入 Plain TeX 文件中。在 LaTeX 中,我可以使用包。我的目标是在 Plain TeX 中使用 Asymptote。所以我需要一些像fromverbatim一样的东西。\verbatim@startverbatim.sty

梅威瑟:

% Plain LuaTeX
\catcode`@=11
% from latex.ltx
\long\def\@ifnextchar#1#2#3{%
    \let\reserved@d=#1%
    \def\reserved@a{#2}%
    \def\reserved@b{#3}%
    \futurelet\@let@token\@ifnch}
\def\@ifnch{%
    \ifx\@let@token\@sptoken
    \let\reserved@c\@xifnch
    \else
    \ifx\@let@token\reserved@d
    \let\reserved@c\reserved@a
    \else
    \let\reserved@c\reserved@b
    \fi
    \fi
    \reserved@c}
\def\:{\let\@sptoken= } \:  % this makes \@sptoken a space token
\def\:{\@xifnch} \expandafter\def\: {\futurelet\@let@token\@ifnch}

\def\@makeother#1{\catcode`#1=12\relax}

Let's try to write.

\newwrite\file
\immediate\openout\file=temp.tmp\relax

\def\verbatimwrite{\begingroup\catcode`\^^M=12\relax
    %\let\do\@makeother\dospecials%%%%%%% PROBLEM! (A)
    \@verbatimwrite}

\begingroup
\catcode`\^^M=12 %
\gdef\@verbatimwrite#1^^M{% Every line must be written separately to save the line breaks.
    \immediate\write\file{\unexpanded{#1}}%
    \@ifnextchar\endverbatimwrite\endgroup\@verbatimwrite}% detect the end of verbatim (B)
\endgroup

\let\endverbatimwrite\relax

\verbatimwrite
123#;^{t}
äöüß

4567\undefined
\endverbatimwrite

\immediate\closeout\file

\bye

有2个问题(也作为代码中的注释):

  • (A):我必须在哪里更改所有其他 catcode?例如,应该可以编写不平衡的括号。如果操作正确,我认为\unexpanded不再需要该命令。
  • (B):您知道如何提高 的检测率吗\endverbatimwrite?我觉得我的方法真的很差。

谢谢。

答案1

你改变 catcode 的时机恰到好处。问题是,\let\do\@makeother \dospecials guard后面\endverbatimwrite不再是控制序列,而是反斜杠字符加上 16 个字母的序列。这导致你的代码失败,因为你的\@ifnextchar测试寻找控制序列 \endverbatimwrite,但从未被找到。

至于检测\endverbatimwrite,您不需要在每一行之后搜索它(您可以,但您不必这样做)。最大的问题还是由于 catcode 的变化:您不再有 ,而是 ,\endverbatimwrite\ e n d v e r b a t i m w r i t e完全不同(并且更难找到\@ifnextchar;您需要某种循环,或多或少像listings检测环境的结束一样)。定义一个查找字符串的分隔宏要容易得多\endverbatimwrite检测环境的结束一样)。定义一个分隔宏来查找具有正确 catcode 的

通常,逐字环境的算法(当然是简单的算法)是:1)获取参数(可选参数,要写入的文件名,或者在本例中是写入流);2)\begingroup;3)\catcodes;4)获取命令/环境的内容;5)\endgroup并处理抓取的字符(最后两个的顺序可能有所不同)。

这是代码的修改版本(基于其中一些形式这里):

\catcode`@=11

\def\@makeother#1{\catcode`#112\relax}
\def\verbatimwrite#1{%
  \begingroup
    \catcode`\^^M=13
    \newlinechar`\^^M
    \let\do\@makeother \dospecials
    \verbwrite@cleanup#1}
\begingroup
  \lccode`\?=`\\
  \lowercase{\endgroup% \
\def\verbwrite@other#1#2?endverbatimwrite{%
  \immediate\write#1{\unexpanded\expandafter
    {\verbwrite@strip@newline#2\relax}}%
  \endgroup}}
\begingroup
  \catcode`\^^M=13
  \gdef\verbwrite@cleanup#1#2^^M{%
    \if\relax\detokenize{#2}\relax
    \else \errmessage{Wrong input `#2' discarded}%
    \fi
    \verbwrite@other#1}
  \gdef\verbwrite@strip@newline#1^^M\relax{#1}
\endgroup

Let's try to write.

\newwrite\file
\immediate\openout\file=temp.tmp\relax

\verbatimwrite\file
123#;^{t}
äöüß}

4567\undefined{
\endverbatimwrite

\immediate\closeout\file

\bye

输出文件包含:

123#;^{t}
äöüß}

4567\undefined{

相关内容