我有以下代码,它设置了一个 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}