我想定义一个带有两个参数的宏,这些参数由可选空格分隔。例如,从以下代码
\def\mymacro #1 #2 {#1:#2 }
\mymacro one two others
我明白了one:two others
。但如果某个参数以控制序列结尾,例如
\mymacro \foo \bar others
我无法得到,\foo:\bar others
因为 TeX 会忽略控制序列后的空格。
我该如何解决这个问题?
[编辑]补充一些背景知识:出于某些原因,我需要将原始命令重新定义为宏,并使其表现得像原始命令。例如,原始命令的参数可以是或或或等<number>
形式。并且空格在原始命令的意义上是可选的。64
"5B
`\a
\foo
答案1
虽然可以定义一个宏来查找可选空格,但是查找<number>
会进行扩展,因此它不像测试抓取的参数是否是控制序列那么简单。通常在这些情况下,会使用临时寄存器,以便 TeX 仍在解析数字(或 dimen、skip、ETC。),然后使用它\afterassignment
来获取值。例如,要获取两个<number>
参数,我们可能会这样做
\catcode`\@=11
\def\mymacro{%
\begingroup
\afterassignment\myacro@auxi\count0=%
}
\def\myacro@auxi{%
\afterassignment\myacro@auxii\count2=%
}
\def\myacro@auxii{%
\edef\next{\noexpand\myacro@auxiii{\the\count0}{\the\count2}}%
\expandafter\endgroup
\next
}
\def\myacro@auxiii#1#2{Values: #1 #2 }
\catcode`\@=12
我使用了两个临时寄存器和一个组来保证它们的“安全”。(用一个寄存器和一个自我重新定义的辅助寄存器也可以实现同样的效果,但会变得很复杂!)然后这将适用于一系列输入语法
\mymacro 1 2 %
\def\foo{1}
\mymacro \foo\space 2 %
\count0=12 %
\newcount\foo
\foo=14
\mymacro\count0 \foo
\mymacro `\A "88
\bye
答案2
也许这可以稍微驯服一下。但这里的宏检查它的参数,看它们是否是控制序列,是否是分支方向,是否不是分支方向。关键是@egreg\@ifismacro
提供给上一个答案注释如下:
\documentclass{article}
\makeatletter
%% see: https://tex.stackexchange.com/a/21469/22413
\def\@ifismacro#1{%
\begingroup\escapechar=-1
\edef\x{\endgroup\def\noexpand\first{\string#1}}\x
\begingroup\escapechar=`\\
\edef\x{\endgroup\def\noexpand\second{\string#1}}\x
\ifnum\pdfstrcmp{\first}{\second}=\z@
\expandafter\@secondoftwo % no backslash in front
\else
\expandafter\@firstoftwo % backslash in front
\fi}
\def\mymacro#1{%%
\def\mycontinue{}%%
\@ifismacro#1%%
{%%
\def\mycontinue{\@m@mymacro{#1}}%%
}{%%
\def\mycontinue{\@a@mymacro #1}%%
}%%
\mycontinue}
\def\@m@mymacro#1#2{%%
\def\mycontinue{}%%
\@ifismacro#2%%
{%%
\def\mycontinue{\@@mymacro {#1} {#2} }%%
}{%%
\def\mycontinue{\@a@mymacro{#1} #2}%%
}%%
\mycontinue}
\def\@a@mymacro#1 #2{%%
\def\mycontinue{}%%
\@ifismacro#2%%
{%%
\def\mycontinue{\@@mymacro {#1} {#2} }%%
}{%%
\def\mycontinue{\@@mymacro #1 #2}%%
}
\mycontinue}
\def\@@mymacro#1 #2 {%%
#1:#2 }
\makeatother
\def\foo{foo}
\def\bar{bar}
\begin{document}
\mymacro one two others
\mymacro \foo \bar others
\mymacro one \bar others
\mymacro \foo two others
\end{document}