如何在命令参数中“稳健地”使用文件内容?

如何在命令参数中“稳健地”使用文件内容?

我有以下代码,它设置了一个 XeLaTeX 文档(用 运行--enable-write18)并定义了两个命令,\showme\prRaise

\documentclass[a4paper,oneside]{memoir}
\usepackage{polyglossia}
\setdefaultlanguage{english}
\usepackage{catchfile}

% ----------------------------------------------------------------------------------------------------------
\newcommand*{\showme}[1]{The value is #1.}

% ----------------------------------------------------------------------------------------------------------
\makeatletter%
\newdimen\pr@Height%

\newcommand{\prRaise}[2]{%
  \setlength{\pr@Height}{\f@size pt}%
  \raisebox{#1\pr@Height}{#2}%
  }%

\makeatother%

% ----------------------------------------------------------------------------------------------------------
\def\cxltxReadA{\CatchFileEdef{\cxltxR}{/tmp/CXLTXtempout.tex}{}}
\def\cxltxReadB{\CatchFileEdef{\cxltxR}{/tmp/CXLTXtempout.tex}{}\cxltxR}

% ----------------------------------------------------------------------------------------------------------
\begin{document}

\showme{foobar}% => ”The value is foobar”.

\showme{\cxltxReadB}% => ”The value is -0.2 .”

\showme{\input{/tmp/CXLTXtempout}}% => ”The value is -0.2 .”

\showme{\immediate\input{/tmp/CXLTXtempout}}% => ”The value is -0.2 .”

A\prRaise{-0.2}{B}C% => "ABC" with B lowered

A\prRaise{-0.2 }{B}C% => "ABC" with B lowered (trailing space shouldn't be a problem)

A\prRaise{\input{/tmp/CXLTXtempout}}{B}C% !!! => Missing number, treated as zero.

A\prRaise{\immediate\input{/tmp/CXLTXtempout}}{B}% !!! => Missing number, treated as zero.

A\prRaise{\cxltxReadB}{B}C% !!! => Missing number, treated as zero.

\cxltxReadA A\prRaise{\cxltxR}{B}C% works

\end{document}

问题是,尝试使用文件内容\input\immediate\input\cxltxReadA...\cxltxR对于这两个命令都有效,但至关重要的是,所有尝试读取文件内容的尝试之内参数prRaise失败。如果它确实有效那就太好了,因为我真正想要做的是调用一些外部程序来进行上下文计算,所以我想在需要它的时候调用那个外部程序。

为什么这两个命令的行为如此不同?定义中的什么\prRaise导致了这些问题?

答案1

正如解释的那样为什么 \input 不可扩展?,LaTeX 版本的\input不可扩展。要将其用于\input您想要的上下文中,作为设置长度的一部分,您需要通过扩展来工作。LaTeX 的\input定义方式有充分的理由,但如果您确实需要扩展,请使用保存的 TeX 原语:

\begin{filecontents*}{\jobname.tmp}
-0.2
\end{filecontents*}
\documentclass{article}
\makeatletter
\newlength\pr@Height
\newcommand\prRaise[2]{%
  \setlength\pr@Height{\f@size pt}%
  \raisebox{#1\pr@Height}{#2}%
}
\let\normalinput\@@input
\makeatother
\begin{document}
A\prRaise{\normalinput \jobname.tmp }{B}C
\end{document}

请注意,同样的问题也适用于例如

A\prRaise{\cxltxReadB}{B}C%

就像\cxltxReadB试图进行一个定义,但它又是不可扩展的。

答案2

首先让我们去掉,它只有在和\immediate之前才有意义,因为这些操作通常在 shipout 期间执行,并且带有前缀,它们是“立即”执行的。\write\openout\closeout\immediate

因此\immediate\input只有一个效果,即一直扩展\input直到找到第一个不可扩展的标记。由于此标记是\let(由 产生\@ifnextchar),因此 TeX 会忽略它\immediate并继续。

\prRaise我会区分“明确”参数和要读取的文件之间的调用。

\begin{filecontents*}{\jobname.tmp}
-0.2
\end{filecontents*}
\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand\prRaise{smm}
 {
  \dim_set:Nn \l_flow_pr_height_dim { \use:c { f@size } pt }
  \IfBooleanTF{#1}
   {% \tl_set_from_file:Nnn is the same as \CatchFileDef
    \tl_set_from_file:Nnn \l_flow_pr_factor_tl { } { #2 }
   }
   {
    \tl_set:Nn \l_flow_pr_factor_tl { #2 }
   }
  \flow_pr_raise:n { #3 }
 }

\dim_new:N \l_flow_pr_height_dim
\tl_new:N \l_flow_pr_factor_tl

\cs_new_protected:Npn \flow_pr_raise:n #1
 {
  \raisebox{ \l_flow_pr_factor_tl \l_flow_pr_height_dim } { #1 }
 }

\ExplSyntaxOff

\begin{document}
A\prRaise{-0.2}{B}C

A\prRaise*{\jobname.tmp}{B}C
\end{document}

在此处输入图片描述

相关内容