在 \input 后​​插入标记

在 \input 后​​插入标记

这个问题的答案应该很简单,但我似乎找不到如何做。我试图使用\afterassignmentmake 语法来制作节标题,然后使用 TeX 的词法分析来\input包含该文件

\def\section#1;{
    \noindent{\bf #1}\par
    \afterassignment\xsection
    \input
}
\def\xsection{
    this text should appear after example.tex's
}
\section SECTION NAME;example

这不起作用,因为分配时,文本 from\xsection出现在 's 之前。我尝试使用宏来切换两者,其中s 和sexample.tex混乱不堪。实现此目的的最简洁方法是什么(仅使用原语,或者,如果需要,使用 Plain TeX)?\expandafter\noexpand

答案1

\input不执行分配,因此您无法保证何时\afterassignment插入标记。使用 ε-TeX,您可以使用\everyeof在输入文件末尾添加标记:

% Example file:
\newwrite\temp
\immediate\openout\temp=example.tex
\immediate\write\temp{Some text\par}
\immediate\closeout\temp

\def\section#1;{%
  \noindent{\bf #1}\par
  \everyeof{\xsection}%
  \input
}
\def\xsection{%
  \everyeof{}%
  this text should appear after example.tex's%
}
\section SECTION NAME;example

\bye

但是,此代码无法处理嵌套的s ,文件内的\section任何 s (any  ) 都不会触发要插入的标记。如果您使用 like ,那么会容易得多,然后文件名将被抓取为参数,并且您可以更好地控制它。\input\section\input\everyeof\section SECTION NAME;{example}


回复您的评论,是的,用空格分隔参数有一些缺陷。如果您作为命令的用户表现良好,那么您的空格分隔方法可能在大多数情况下都会有效。但用户不守规矩,这是事实 ;-)

例如,执行 之后\def\ample{ample.tex },命令\input ex\ample将执行您期望的操作,但将其作为空格分隔的参数抓取取决于您在 之后输入的内容\ample。另一个问题是,某些 TeX 发行版(至少据我所知,TeXLive 和 MiKTeX)允许您输入带空格的文件名,如果您将名称括在引号中,例如\input "example file.tex"(该实现还允许您\input example" "file.tex\input "e"x"a"m"p"l"e "f"i"l"e"."t"e"x",并且都输入同一个文件,这有点奇怪)。您的空格分隔方法也不会接受带引号的文件名。

如果您不介意多写几行代码,这里有一种方法(据我测试)几乎 完全模拟了 TeX 的文件名扫描器1。\scanfilename{<code>}<filename>我定义了一个宏,它<filename>遵循 TeX 的文件名扫描规则(扩展可扩展标记,在两个 之间的空格处停止",忽略所有"),然后运行<code>​​,其中文件名可用作#1,因此您的定义变得容易得多,因为您可以在抓取文件名后进行控制。另外,它在 Knuth TeX 中有效 :-)

另外,使用这个你可以嵌套多个\sections 和\input

% Example file:
\newwrite\temp
\immediate\openout\temp="example file.tex"
\immediate\write\temp{Some text\par
    \noexpand\section Another section;"another example.tex"\par
    Yet more text\par}
\immediate\closeout\temp
\immediate\openout\temp="another example.tex"
\immediate\write\temp{More text\par}
\immediate\closeout\temp

\catcode`\@=11
\def\@firstoftwo#1#2{#1}
\def\@secondoftwo#1#2{#2}
\def\bool@flip#1{\ifodd#1\chardef#1=0 \else\chardef#1=1 \fi\relax}
\def\bool@false#1{\chardef#1=0\relax}
\def\bool@true#1{\chardef#1=1\relax}
\def\scanfilename#1{%
  \def\filename@action##1{#1}%
  \begingroup
    \def\curfile{}%
    \bool@false\in@quote@bool
    \scan@file@name@peek}
\def\file@name@end{%
    \edef\file@temp{%
  \endgroup
  \noexpand\filename@action{\curfile}}\file@temp}
\def\more@name#1{%
  \edef\space@action##1{%
    \ifodd\in@quote@bool
      \noexpand\add@token{##1}%
    \else \noexpand\file@name@end
    \fi}%
  \if\noexpand"\noexpand#1%
    \expandafter\@firstoftwo
  \else \expandafter\@secondoftwo
  \fi
    {\bool@flip\in@quote@bool
     \add@token{}}%
    {\if\space\noexpand#1%
       \expandafter\space@action
     \else \expandafter\add@token
     \fi{#1}}}
\def\add@token#1{%
  \toks@\expandafter{\curfile}%
  \edef\curfile{\the\toks@#1}%
  \afterassignment\scan@file@name@peek
  \let\scratch@token= }
\def\scan@file@name@peek{%
  \futurelet\peek@token\scan@file@name@next}
\def\q@nil{\q@nil}
\def\scan@file@name@next{%
  \token@if@expandable\peek@token
    {\expandafter\scan@file@name@peek}
    {\edef\sctratch@token{%
       \noexpand\dissect@meaning
       \meaning\peek@token\space\space\space
       \noexpand\q@nil\noexpand\q@stop}%
     \sctratch@token}}
\def\token@if@expandable#1{%
  \expandafter\ifx\noexpand#1#1%
    \expandafter\@secondoftwo
  \else \expandafter\@firstoftwo
  \fi}
\def\dissect@meaning#1 #2 #3 #4#5\q@stop{%
  \pm@strcmp{#2}{}{\unexp@end@name}{}%
  \pm@strcmp{#2}{letter}{\add@char@token{#3}}{}%
  \pm@strcmp{#2}{character}{\add@char@token{#3}}{}%
  \pm@strcmp{#2}{space}{\add@char@token{ }}{}%
  \pm@strcmp{#3}{character}{\add@char@token{#4}}{}%
  \wrong@char}
\def\wrong@char{\errmessage{Wrong character in file name...}}
\def\unexp@end@name#1\wrong@char{\file@name@end}
\def\add@char@token#1#2\wrong@char{\more@name{#1}}
\def\pm@detokenize#1#2{\def#1{#2}%
  \edef#1{\expandafter\strip@prefix\meaning#1}}
\def\strip@prefix#1>{}
\def\pm@strcmp#1#2{%
  {\pm@detokenize\tmpa{#1}%
   \pm@detokenize\tmpb{#2}%
   \expandafter}%
  \ifx\tmpa\tmpb
    \expandafter\@firstoftwo
  \else \expandafter\@secondoftwo
  \fi}
\catcode`\@=12

\def\section#1;{%
  \noindent{\bf #1}\par
  \scanfilename{%
    \input "##1"\expandafter\relax
  \xsection}%
}
\def\xsection{this text should appear after example.tex's}

\section SECTION NAME;"example file.tex"

\bye

(代码最初是用 编写的expl3,因此它短得多;ε-TeX 使生活变得轻松得多;-)


[1] TeX 知道行尾,因此:

\input "example
file.tex"

将输入example.tex然后排版file.tex",而:

\scanfilename{\input"#1" }"example
file.tex"

将输入,example file.tex因为\endlinechar变成了空格。

相关内容