我正在尝试采用这个 TeX 片段并将其用作宏的基础。
\centerline{\def\epsfsize#1#2{0.7#1} \epsfbox{1.01couet.eps}}
我正在努力解决一些需要解决的问题,因为我实际上正在重新定义一个填充相当大的项目的宏。我认为我可以做的是类似以下的事情:
\def\myfig#1#2#3#4{\dimen1=#4 \divide\dimen1 by 1000
\centerline{\def\epsfsize#1#2{{#4}{#1}} \epsfbox{#3}}}
这显然是错误的,可能有多种错误。我需要取参数 #4 并将其除以 1000 以用作比例(0.7 是上一个代码片段)。我知道 dimen1 不适用于无量纲量,但我找不到与此类主题相关的任何文档。
请注意,前两个参数暂时不会使用。
有没有涵盖这一问题的好的文档?
答案1
我的系统上没有1.01couet.eps
。但是每个较新的 TeX 发行版都有example-image-a.eps
。
因此,在下面的代码片段中我将使用后者。;-)
如果我理解正确的话,\myfig
的第四个参数表示任何因子。
该因子应除以 1000(十进制)。
其结果应作为比例因子传递到 的定义中\epsfsize
?
你可以通过维度来计算。要点是:
\the\dimension1
根据单位得出维度寄存器 1 中保存的值pt
。
例如,\the\dimension1
→ 30.74pt
。
因此,按照 进行计算pt
,当使用结果作为数字而不是维度时,去掉短语pt
。
采用这种计算方法,结果不会很精确。
可能是其中一个包FP或者前列腺素(pgf 的数学引擎)对您来说很有趣。
下面的代码片段是否提供了或多或少正确的比例因子\epsfsize
?
\input epsf.tex
\long\def\PassFirstToSecond#1#2{#2{#1}}%
\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
\begingroup
\catcode `P=12 %
\catcode `T=12 %
\lowercase{%
\def\x{%
\def\RomannumeralDrivenRempt##1.##2PT{%
0\ifnum##2>0 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{ ##1.##2}{ ##1}%
}%
}%
}%
\expandafter\endgroup\x%
\def\RomannumeralDrivenStrippt{\expandafter\RomannumeralDrivenRempt\the}%
\def\myfig#1#2#3#4{%
\begingroup
\dimen1=#4pt %
\dimen1=.001\dimen1 %
\expandafter\endgroup
\expandafter\centerline\expandafter{%
\expandafter\PassFirstToSecond\expandafter{%
\romannumeral\RomannumeralDrivenStrippt\dimen1 ##1%
}{\def\epsfsize##1##2}%
%%%
\show\epsfsize
%%%
\epsfbox{#3}%
}%
}%
\myfig{Unused 1}{Unused 2}{example-image-a.eps}{1000}
\myfig{Unused 1}{Unused 2}{example-image-a.eps}{700}
\myfig{Unused 1}{Unused 2}{example-image-a.eps}{200}
\myfig{Unused 1}{Unused 2}{example-image-a.eps}{40}
\bye
以下是相同的代码,但带有一些解释:
我认为这是\epsfsize
来自哪里\epsfbox
:
\input epsf.tex
将第一个参数嵌套在第二个参数后面的括号中 - 这样,构成第一个参数的标记可以转换为构成第二个参数的标记的参数:
\long\def\PassFirstToSecond#1#2{#2{#1}}%
选择两个参数中的第一个:
\long\def\firstoftwo#1#2{#1}%
选择两个参数中的第二个:
\long\def\secondoftwo#1#2{#2}%
上面我写道:“...按照 进行计算pt
,当使用结果不是维度而是数字时,删除短语pt
“。问题是,使用\the\dimen1
→时30.74pt
,组成短语的字符标记pt
不是类别代码 11(字母),而是类别代码 12(其他)。所以我们需要将p
类别代码 12 和t
类别代码 12 放入代码中,同时还要让这些字符在类别代码 11 中可用,以便它们可以在宏名称中使用。因此,在一个组内,暂时将这些字符的大写变体的类别代码更改为 12。从这些大写变体中,您可以通过 类别代码 12 获得小写变体\lowercase
。
\begingroup
\catcode `P=12 %
\catcode `T=12 %
\lowercase{%
\def\x{%
\def\RomannumeralDrivenRempt##1.##2PT{%
0\ifnum##2>0 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{ ##1.##2}{ ##1}%
}%
}%
}%
\expandafter\endgroup\x%
根据上述定义\x
,
\def\x{%
\def\RomannumeralDrivenRempt##1.##2pt{%
0\ifnum##2>0 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{ ##1.##2}{ ##1}%
}%
}%
,但该分隔符pt
后面的字符将属于类别代码 12(其他)。##2
##2
因此,扩大\x
定义后将\RomannumeralDrivenRempt
是
\def\RomannumeralDrivenRempt#1.#2pt{%
0\ifnum#2>0 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{ #1.#2}{ #1}%
}%
pt
,其后面的字符为#2
类别#2
代码 12(其他)。(正如\x
组内所定义的,它需要在结束组之前进行扩展,但要使传递的标记出现在结束组的\x
标记后面。这就是in的用途。)\endgroup
\expandafter
\expandafter\endgroup\x
乍一看,这个定义看起来很奇怪。但如果\RomannumeralDrivenRempt
在 之前\romanumeral
和之后加上400.23pt
,则会得到以下内容:
\romannumeral\RomannumeralDrivenRempt400.23pt
这反过来又产生:
步骤1:
% romannumeral-expansion in progress
\RomannumeralDrivenRempt400.23pt
第2步:
% romannumeral-expansion in progress
0\ifnum23>0 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{ 400.23}{ 400}%
步骤3:
% romannumeral-expansion in progress
% \romannumeral finds the digit 0 and keeps searching for more digits
% or a space-token that terminates the number and gets discarded.
\ifnum23>0 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{ 400.23}{ 400}%
步骤 4:\ifnum
比较产生“真实”分支:
% romannumeral-expansion in progress
% \romannumeral found the digit 0 and keeps searching for more digits
% or a space-token that terminates the number and gets discarded.
\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{ 400.23}{ 400}%
步骤 5: \expandafter
“命中” else 分支并且该 else 分支被删除:
% romannumeral-expansion in progress
% \romannumeral found the digit 0 and keeps searching for more digits
% or a space-token that terminates the number and gets discarded.
\firstoftwo
{ 400.23}{ 400}%
步骤 6: \firstoftwo
获取第一个参数:
% romannumeral-expansion in progress
% \romannumeral found the digit 0 and keeps searching for more digits
% or a space-token that terminates the number and gets discarded.
<space token>400.23
步骤 7:现在\romannumeral
“找到”空格标记。空格标记用于构成要转换\romannumeral
为罗马数字的数字序列的终止符。该终止符将被丢弃,\romannumeral
要转换的数字所采用的数字序列仅由数字组成,0
而0
不是正数,而 则按\romannumeral
如下方式处理非正数:它只是吞下它们而不提供任何标记作为回报:
% romannumeral-expansion done. \romannumeral found the non-positive
% number 0 and silently swallowed it without delivering any token
% in return:
400.23
现在让我们继续代码:
上面我写道:“但是如果\RomannumeralDrivenRempt
前面\romanumeral
和后面都有类似的东西400.23pt
,则会得到以下内容:......“因此需要一种机制来提供以下尾随短语:
\def\RomannumeralDrivenStrippt{\expandafter\RomannumeralDrivenRempt\the}%
(根据上述定义
\romannumeral\RomannumeralDrivenStrippt\dimen1
产量:
步骤1:
%\romannumeral-expansion in progress
\RomannumeralDrivenStrippt\dimen1
第2步:
%\romannumeral-expansion in progress
\expandafter\RomannumeralDrivenRempt\the\dimen1
步骤 3: \expandafter“命中” \
%\romannumeral-expansion in progress
\RomannumeralDrivenRempt400.23pt
这是 扩展链的第一步\RomannumeralDrivenRempt
。
)
现在让我们继续代码:
\def\myfig#1#2#3#4{%
\begingroup
\dimen1=#4pt %
\dimen1=.001\dimen1 %
\expandafter\endgroup
\expandafter\centerline\expandafter{%
\expandafter\PassFirstToSecond\expandafter{%
\romannumeral\RomannumeralDrivenStrippt\dimen1 ##1%
}{\def\epsfsize##1##2}%
%%%
\show\epsfsize
%%%
\epsfbox{#3}%
}%
}%
\myfig{Unused 1}{Unused 2}{example-image-a.eps}{1000}
\myfig{Unused 1}{Unused 2}{example-image-a.eps}{700}
\myfig{Unused 1}{Unused 2}{example-image-a.eps}{200}
\myfig{Unused 1}{Unused 2}{example-image-a.eps}{40}
\bye
让我们展示一下扩展链
\myfig{Unused 1}{Unused 2}{example-image-a.eps}{700}
步骤1:
\begingroup
\dimen1=700pt %
\dimen1=.001\dimen1 %
\expandafter\endgroup
\expandafter\centerline\expandafter{%
\expandafter\PassFirstToSecond\expandafter{%
\romannumeral\RomannumeralDrivenStrippt\dimen1 ##1%
}{\def\epsfsize##1##2}%
%%%
\show\epsfsize
%%%
\epsfbox{example-image-a.eps}%
}%
步骤 2:在组内对 进行临时分配,\dimen1
并进行“\expandafter
跳跃”,以获取形成扩展的标记,\romannumeral\RomannumeralDrivenStrippt\dimen1
如上所述,在\endgroup
关闭组的标记后面:
\begingroup
\dimen1=700pt %
\dimen1=.001\dimen1 %
\endgroup
\centerline{%
\PassFirstToSecond{%
.7##1%
}{\def\epsfsize##1##2}%
%%%
\show\epsfsize
%%%
\epsfbox{example-image-a.eps}%
}%
组内的东西到达 TeX 的胃里并被消化。剩下的有趣的部分是:
\centerline{%
\PassFirstToSecond{%
.7##1%
}{\def\epsfsize##1##2}%
%%%
\show\epsfsize
%%%
\epsfbox{example-image-a.eps}%
}%
步骤 3:由于\PassFirstToSecond
这种情况,如下所示:
\centerline{%
\def\epsfsize##1##2{.7##1}%
%%%
\show\epsfsize
%%%
\epsfbox{example-image-a.eps}%
}%