我有一些宏可以扩展为一些文本,但当一起使用时,它们应该扩展为完全不同的东西。在此示例中:
\foo
->x
\bar
->y
\foo\bar
->Hello World
原则上,使用\if...
构造来实现这一点是可行的,但是需要大量的输入,因此我尝试使用\csname
,但无法使其工作:
\documentclass{article}
\newcounter{mycounter}
\newcommand\ifalternatetext[2]{\ifnumcomp{\value{mycounter}}{>}{0}{\addtocounter{mycounter}{-1}#1}{#2}}
\def\foo{\addtocounter{mycounter}{1}x}
\def\bar{\ifalternatetext{y}{z}}
\def\bazxy{Hello World}
\newcommand\print[2]{\csname baz#1#2\endcsname{}}
\begin{document}
This works: `\print{x}{y}'
This doesn't: `\print{\foo}{\bar}'
\end{document}
答案1
和{}
之后的括号阻止了 OP 第二次调用中的宏的扩展。\foo
\bar
\print
\documentclass{article}
\def\foo{x}
\def\bar{y}
\def\bazxy{Hello World}
\newcommand\print[2]{\csname baz#1#2\endcsname{}}
\begin{document}
This works: `\print{x}{y}'
This also works: `\print{\foo}{\bar}'
\end{document}
答案2
你不能在里面做作业\csname...\endcsname
。一个很好的参考是\csname 和 \endcsname 到底起什么作用?我的答案是,你可以在那里找到
这个技巧还有许多其他有趣的用途。但我们应该始终记住,TeX 不会完全扩展它在这种背景下发现了什么,并且仅限字符必须保留。
由于\addtocounter{mycounter}{1}
依赖于最终执行\global\advance\c@mycounter by 1
它是不允许的\csname...\endcsname
。
如果您想要的只是\foo
在跟随\bar
或不跟随时表现不同,请使用\@ifnextchar
:
\makeatletter
\newcommand{\foo}{\@ifnextchar\baz{\foobaz\@gobble}{x}}
\newcommand{\baz}{y}
\newcommand{\foobaz}{Hello world}
\makeatother
请注意,\@gobble
将删除多余的\baz
令牌。
完整示例
\documentclass{article}
\makeatletter
\newcommand{\foo}{\@ifnextchar\baz{\foobaz\@gobble}{x}}
\newcommand{\baz}{y}
\newcommand{\foobaz}{Hello world}
\makeatother
\begin{document}
Separate: \foo{} and \baz.
Contiguous: \foo\baz
\end{document}
这是使用宏的不同方法\print
:
\documentclass{article}
\usepackage{etoolbox}
\makeatletter
\providecommand\@secondofthree[3]{#2}
\providecommand\@thirdofthree[3]{#3}
\newcommand{\foo}{x\expandafter\@secondofthree}
\newcommand{\fuu}{T\expandafter\@secondofthree}
\newcommand{\baz}{\@secondoftwo{y}{z}}
\makeatother
\newcommand\bazz{Normal}
\newcommand\bazTy{Ops}
\newcommand\bazxy{Hello World}
\newcommand\print[2]{\csname baz#1#2\endcsname}
\begin{document}
`\print{\foo}{\baz}'
`\print{\fuu}{\baz}'
`\print{}{\baz}'
\end{document}
宏\print{\foo}{\baz}
变为
\csname baz\foo\baz\endcsname
并且不断扩大\foo
。
\csname bazx\expandafter\@secondofthree\baz\endcsname
现在\expandafter
导致扩张\baz
并消失
\csname bazx\@secondofthree\@secondoftwo{y}{z}\endcsname
其中扩展\@secondofthree
选择y
,给出
\csname bazxy\endcsname
当\print{}{\baz}
使用时,我们有
\csname baz\@secondoftwo{y}{z}\endcsname
和\@secondoftwo
选择z
,给予\csname bazz\endcsname
。
人们可以安装一个抽象层,它最终会完成同样的功能,但使定义更容易:
\documentclass{article}
\usepackage{etoolbox}
\makeatletter
\providecommand\@secondofthree[3]{#2}
\providecommand\@thirdofthree[3]{#3}
\newcommand{\newprefixcommand}[2]{%
\newcommand{#1}{#2\expandafter\@secondofthree}%
}
\newcommand{\newalternatecommand}[3]{%
\newcommand{#1}{\@secondoftwo{#2}{#3}}%
}
\makeatother
\newcommand\print[2]{\csname baz#1#2\endcsname}
\newprefixcommand{\foo}{x}
\newprefixcommand{\fuu}{T}
\newalternatecommand{\baz}{y}{z}
\newcommand\bazz{Normal}
\newcommand\bazTy{Ops}
\newcommand\bazxy{Hello World}
\begin{document}
`\print{\foo}{\baz}'
`\print{\fuu}{\baz}'
`\print{}{\baz}'
\end{document}
答案3
我现在有了并分配一个临时宏,然后可以在内使用它,而不是直接将\foo
和\bar
放入:\csname
\foo
\bar
\csname
\documentclass{article}
\usepackage{etoolbox}
\newcounter{@mycounter}
\makeatletter
\def\@foo@out{}
\def\@bar@out{}
\newcommand\ifalternatetext[2]{%
\ifnumcomp{\value{@mycounter}}{>}{0}{%
\addtocounter{@mycounter}{-1}%
\gdef\@bar@out{#1}%
}{%
\gdef\@bar@out{#2}%
}}
\newcommand\@foohelper[1]{%
\addtocounter{@mycounter}{1}%
\gdef\@foo@out{#1}%
}
\def\foo{\@foohelper{x}}
\def\bar{\ifalternatetext{y}{z}}
\def\bazxy{Hello World}
\newcommand\print[2]{#1#2\csname baz\@foo@out\@bar@out\endcsname{}}
\makeatother
\begin{document}
`\print{\foo}{\bar}'
\end{document}