扩展 \csname 中的宏

扩展 \csname 中的宏

我有一些宏可以扩展为一些文本,但当一起使用时,它们应该扩展为完全不同的东西。在此示例中:

  • \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}

相关内容