我花了大量时间在参考资料和论坛中寻找我在此提出的问题的答案。
我想编写一个宏,将单词作为参数,而无需使用括号来通知这一点。这将是一个智能宏,可以识别什么应该是参数的组成部分,逐个标记地构造它,直到找到不合适的候选者(在完成宏本身后将被完整替换)。例如
\def\km#1{% definition: only accept numbers: writes the unit after the subsequent integer word (parameter)%}
\def\mathstyle#1{% definition: accept anything except point and space: put parameter in mathmode (assumes that is called in "text mode" for simplification)%}
% usage
The radius of the Earth is about \km 6300. %%
%% *\km 6300.* expands to 6300 $km$.
The distance between \mathstyle Point-A to \mathstyle Point-B is \km 20 assume that the Earth is plain.
%% puts Point-A and Point-B between math shifts
简而言之,为了实现这一点,据称我需要逐个检查字符并调用处理宏,直到它获取无法识别的标记。
问题是:在许多情况下,TeX 会忽略宏后的空格。因此,我无法创建处理空格的宏(将所有用空格分隔的单词连接起来)。
我该如何修复?现在如何销毁宏后的空格?
答案1
我不确定我是否理解了这个问题(“现在如何销毁宏后的空格?”这个问题似乎与上面的上下文无关,也许举个例子会很有启发)。要回答获取单个单词作为参数的问题,您可以使用扫描标记逐个标记\futurelet
并测试是否出现字母
\protected\def\getword#1{%
\begingroup \toks0{}\toks1{#1}%
\futurelet\next\getwordA
}
\def\getwordA{\ifcat A\noexpand\next \expandafter\getwordB \else \expandafter\getwordC \fi}
\def\getwordB#1{\toks0\expandafter{\the\toks0 #1}\futurelet\next\getwordA}
\def\getwordC{\edef\tmp{\endgroup \the\toks1{\the\toks0}}\tmp}
\def\textbf#1{{\bf#1}} \def\textit#1{{\it#1\/}} % demo
\getword\textbf Foo bar
{\getword\textit baz} fu
\bye
通过添加一些额外的检查,可以轻松允许破折号、下划线等。
答案2
有一些病态情况需要测试,例如如何处理中的小数点\km
。幸运的是,逻辑可以构建到令牌循环中,并且tokcycle
可以从纯文本中调用。
\input tokcycle.tex
\def\aborttoks{\tcpush{\empty\endtokcycraw}}
\newif\ifdotless
\xtokcycleenvironment\km
{\tctestifnum{`##1<`0}{%
\ifdotless\ifx.##1\addcytoks{##1}\dotlessfalse
\else\aborttoks\fi\else\tcpush{##1}\aborttoks\fi}{%
\tctestifnum{`##1>`9}{\aborttoks}{\addcytoks{##1}}}}
{\tcpushgroup{##1}\aborttoks}
{\tcpush{##1}\aborttoks}
{\tcpush{##1}\aborttoks}
{\dotlesstrue}
{\addcytoks{\kern2pt km}}
Testing \km3., \km 4000 and \km 2.3. Next sentence.
\bye
答案3
如果您可以使用 e-TeX 扩展(即pdftex
),您就可以利用expl3
。
\input expl3-generic
\ExplSyntaxOn
\cs_new_protected:Npn \mathstyle
{
\peek_regex_replace_once:nnF
{ (.*?)(\.|\s) } % search anything up to a period or space
{ \c{ensuremath}\cB\{\1\cE\}\2 } % replace with \ensuremath{<tokens>}<period or space>
{} % do nothing if no match
}
\cs_new_protected:Npn \km
{
\peek_regex_replace_once:nnF
{ ([[:digit:]]*) }
{ \c{ensuremath}\cB\{\1\c{kilometers}\cE\} } % replace
{} % do nothing if no match
}
\cs_new_protected:Npn \ensuremath #1
{
\mode_if_math:TF { #1 } { $#1$ }
}
\cs_new_protected:Npn \kilometers { \,\rm km }
\ExplSyntaxOff
The distance between \mathstyle {\rm Point-}A to $\mathstyle {\rm Point-}B$ is \km 20, assume
that the Earth is plain and no wider than $\km 100000$.
\bye
如您所见,宏在文本和数学模式下都有效。