![如何 \read 一个命令并返回结果?](https://linux22.com/image/444174/%E5%A6%82%E4%BD%95%20%5Cread%20%E4%B8%80%E4%B8%AA%E5%91%BD%E4%BB%A4%E5%B9%B6%E8%BF%94%E5%9B%9E%E7%BB%93%E6%9E%9C%EF%BC%9F.png)
作为如何将文件内容用作长度的数值?,我正在尝试这样做(我确实需要读取data.txt
这个新命令里面的文件并在稍后调用该命令时使用该值):
\documentclass{article}
\usepackage{calc}
\begin{document}
\newcommand\x{
\newread\foo
\openin\foo=data.txt
\read\foo to \temp
\temp
}
\setlength\parskip{1pt * \x}
\end{document}
我越来越:
! Missing number, treated as zero.
<to be read again>
\global
l.35 \setlength\parskip{1pt * \x}
怎么了?
答案1
您可以这样做,但需要 LuaTeX。您可以使用 \beginlocalcontrol/\endlocalcontrol 定义一个代码块,该代码块在 TeX 的扩展阶段完全执行(包括打开文件):
\documentclass{article}
\usepackage{calc}
% First define \beginlocalcontrol based on tex.runtoks
\newluafunction\beginlocalcontrol
\directlua{lua.get_functions_table()[\the\allocationnumber] = function() return tex.runtoks(token.get_next) end}
\luadef\beginlocalcontrol\allocationnumber
\begin{document}
\newcommand\x{%
\beginlocalcontrol % This block gets executed during expansion
\begingroup % Let's keep our definitions local to avoid confusion macros which might not expect definitions to change during expansion
\newread\foo
\openin\foo=data.txt
\read\foo to \temp
\closein\foo
\expandafter\endgroup % The two \expandafter's ensure that the final \temp gets the value from inside of the \endgroup and \endlocalcontrol blocks.
\expandafter\endlocalcontrol
\temp
}
\setlength\parskip{1pt * \x}
\end{document}
我建议至少移动\newread \foo
命令的外部,否则每次扩展宏时都会浪费一个输入文件。
答案2
其实这个问题恰好是可以解决的:
\documentclass{article}
\begin{document}
\makeatletter
\setlength\parskip{\@@input{b.tex}pt}
\typeout{\the\parskip}
\setlength\parskip{\dimexpr 1pt*\@@input{b.tex}\relax}
\typeout{\the\parskip}
\makeatother
\end{document}
假设b.tex
包含123
,则两者都会打印出来123.0pt
。
答案3
\read
不可扩展,但本身就是一个赋值命令。
因此,它不能在执行另一个赋值命令(如)的过程中执行\setlength
。
当您打算定义临时宏时,\x
您可以这样做:
\begin{filecontents*}{mydata.txt}
8
\end{filecontents*}
\documentclass{article}
\usepackage{calc}
\newread\foo
\begin{document}
\immediate\openin\foo=mydata.txt
\immediate\read\foo to \x
\immediate\closein\foo
%\setlength\parskip{1pt * \x}
\setlength\parskip{\x pt}
\showthe\parskip
\end{document}
\@@input
是 LaTeX 2ε 的可扩展 TeX 原语的副本\input
。/
\input
无法\@@input
在直接获取一组标记以形成宏参数的过程中执行,因为无论如何都会遇到文件末尾,而该文件末尾将被视为标记\outer
。
但您可以安排事物,使其不被处理为宏参数:
\begin{filecontents*}{mydata.txt}
8
\end{filecontents*}
\documentclass{article}
\begin{document}
\parskip=\csname @@input\endcsname mydata.txt pt %
%\parskip=\dimexpr1pt*(\csname @@input\endcsname mydata.txt )\relax
\showthe\parskip
\end{document}
答案4
既然你要完成一项作业,那么可扩展性就不是一个因素。
最简单的方法是定义一个合适的命令,比如
\setlengthfromfile{<length>}{<file>}{<expression>}
<length>
您要设置的寄存器在哪里,<file>
您要从中读取值的文件在哪里,并<expression>
包含#1
表示文件内容的文件,因此您的情况是
\setlengthfromfile{\parskip}{data.txt}{1pt * #1}
带有示例的代码:
\begin{filecontents*}{\jobname.dat}
20
\end{filecontents*}
\documentclass{article}
\ExplSyntaxOn
\NewDocumentCommand{\setlengthfromfile}{mmm}
{% #1 = length parameter
% #2 = file name
% #3 = expression
\yegor_setlengthfromfile:nnn { #1 } { #2 } { #3 }
}
\cs_new:Nn \__yegor_setlengthfromfile_aux:n { } % initialize
\cs_generate_variant:Nn \__yegor_setlengthfromfile_aux:n { V }
\tl_new:N \l__yegor_setlengthfromfile_tl
\cs_new_protected:Nn \yegor_setlengthfromfile:nnn
{
\file_get:nnN { #2 } { } \l__yegor_setlengthfromfile_tl
\cs_set:Nn \__yegor_setlengthfromfile_aux:n { #3 }
\skip_set:Nn #1 { \__yegor_setlengthfromfile_aux:V \l__yegor_setlengthfromfile_tl }
}
\ExplSyntaxOff
\setlengthfromfile{\parskip}{\jobname.dat}{1pt * #1}
\showthe\parskip
\setlengthfromfile{\parskip}{\jobname.dat}{1pt * #1-12pt}
\showthe\parskip
\setlengthfromfile{\parskip}{\jobname.dat}{#1\parskip}
\showthe\parskip
\setlengthfromfile{\parskip}{\jobname.dat}{#1pt plus 0.1pt}
\showthe\parskip
\stop
控制台将显示
(./yegordim.dat
)
> 20.0pt.
l.31 \showthe\parskip
?
(./yegordim.dat)
> 8.0pt.
l.34 \showthe\parskip
?
(./yegordim.dat)
> 160.0pt.
l.37 \showthe\parskip
?
(./yegordim.dat)
> 20.0pt plus 0.1pt.
l.40 \showthe\parskip
在第三个例子中,我们重用了以前的值\parskip
。