在文件上书写并输入

在文件上书写并输入

我正在尝试重新定义一个\tableofcontents类似命令。

我是这样进行的:将显示的元素写入文件,当我想要显示时输入该文件。

如果我知道 toc 将在文档的开头(或结尾)被调用,那就没问题:我所要做的就是将\openout(或\closeout)命令添加到toc命令中。但是,我不希望在这种假设下工作(主要是因为我不是唯一使用该代码的人,而且我想避免不明显的副作用)。

因此,我希望\openout和命令在和\closeout时自动发出。问题是,在这种情况下,我无法将辅助文件放在文档中间。我一直试图将文件的内容存储在宏中,但我遇到了各种问题,我猜这些问题与扩展有关。\begin{document}\end{document}\input\begin{document}

浏览了一些相关问题后,我设法编写了以下代码:

\documentclass{article}

\newwrite\sommaire

\AtBeginDocument{%
  \immediate\openout\sommaire=\jobname.som%
}
\AtEndDocument{%
  \immediate\closeout\sommaire}

\newcommand{\sommaireline}[1]{%
  \immediate\write\sommaire{#1}
}

\makeatletter
\IfFileExists{\jobname.som}%
{\edef\mysommaire{\@@input \jobname.som }} 
{\edef\mysommaire{\message{No file \jobname.som}}}
\makeatother

\begin{document}

\sommaireline{aaaaa}

\mysommaire

\sommaireline{bbbbb}

\end{document}

但它仍然不起作用,现在我不明白为什么。

更准确地说,第一次编译顺利,文件也.som按预期写入,但第二次编译失败,如下所示:

ERROR: File ended while scanning definition of \mysommaire.
...
ERROR: Too many }'s

都在第一线上\edef

一些相关问题:

答案1

只需使用 Heiko Oberdiek 的catchfile包:

\documentclass{article}
\usepackage{catchfile}
\newwrite\sommaire

\AtBeginDocument{\immediate\openout\sommaire=\jobname.som }
\AtEndDocument{\immediate\closeout\sommaire}

\newcommand{\sommaireline}[1]{%
  \immediate\write\sommaire{#1}
}

\IfFileExists{\jobname.som}%
  {\CatchFileDef\mysommaire{\jobname.som}{}}
  {\def\mysommaire{\message{No file \jobname.som}}}

\begin{document}

X\sommaireline{aaaaa}

\mysommaire

\sommaireline{bbbbb}X

\end{document}

\CatchFileDef例如,您可以使用最后一个参数来进行分配

\CatchFileDef\mysommaire{\jobname.som}{\endlinechar=-1 }

将抑制输入文件中因行尾字符而产生的最后一个空格。

答案2

[完全误导性的代码和声明被撤回]

[strike] 因此,诀窍在于,要输入到标记列表或宏中的文件必须以\endinput. 结尾。[/strike] 对不起,我在这里出丑了。

我使用以下方法维护我的初步答案\read


(在下面的行中,将所有部分替换为,.toc以便.som更接近对 T.Verron 的回复)

几周前,当我开发自己的软件包时,尝试将文件放入标记列表时遇到了类似的问题\input。因此,我现在这样做:.toc

\newtoks\my@toctoks
\def\my@readtoc#1{%
  \ifeof #1
     \let\my@nextread\@gobble
     \global\my@toctoks=\expandafter{\the\my@toctoks}%
  \else
     \let\my@nextread\my@readtoc
     \read #1 to \my@buffer
     \my@toctoks=\expandafter\expandafter\expandafter
       {\expandafter\the\expandafter\my@toctoks\my@buffer}%
  \fi
  \my@nextread{#1}}
\IfFileExists{\jobname .toc}
    {{\endlinechar=-1 \makeatletter
        \newread\my@tf
        \openin\my@tf\@filef@und
           \my@readtoc\my@tf
        \closein\my@tf}}{}

这是为了读取.toc文件(而不是立即排版)。请注意,我在我的包中放了,但这是出于某些特定原因。后果是最后\endlinechar=-1不会有,而如果你不修改,TeX 在读取输入流时会生成一个。\par\endlinechar

关于开始书写,您可以从命令内部获取代码\@starttoc。如果您这样做,则其他包或宏将\begin{document}无法再输入文件.toc,因此最好只在第一次排版目录时这样做。

在我的软件包中,我也做了这些事情,\begin{document}但是在最新版本(尚未在 CTAN 上)中,我.toc按照上述方式读取文件,\usepackage并在第一个 TOC 排版命令中打开进行写入。

答案3

我找到了一种方法,利用了这样一个事实:read操作总是必须找到匹配的括号,并读取行直到括号匹配为止。诀窍就是用\jobname.som括号开始文件,用括号结束文件。但是\write也需要匹配的表达式,所以我们做了一些 catcode hackery。

\documentclass{article}

\newcommand{\sommaireline}[1]{\immediate\write\sommaire{#1}}

\begingroup
\catcode1=12
\catcode2=12
\AtBeginDocument{\newwrite\sommaire
                 \immediate\openout\sommaire=\jobname.som
                 \sommaireline{^^A}}
\AtEndDocument  {\sommaireline{^^B}}

\catcode1=1
\catcode2=2
\IfFileExists{\jobname.som}%
  {\newread\somfile 
   \openin\somfile=\jobname.som
   \read\somfile to \mysomm
   \expandafter\gdef\expandafter\mysommaire\mysomm}
  {\gdef\mysommaire{No file \jobname.som}}
\endgroup

\begin{document}

X\sommaireline{aaaaa}

\mysommaire

\sommaireline{bbbbb}X

\end{document}

相关内容