我应该如何 /protect 此命令以便在 \csname 中使用?

我应该如何 /protect 此命令以便在 \csname 中使用?

在学习如何使用的过程中\csname,我尝试创建一个宏,允许人们指定整数作为参数,然后会产生一些特定于参数的内容,如下所示:

\DoContent{1}{3}

我当前的完整示例尝试:

\documentclass[10pt]{article}

\usepackage{xifthen}

%End-Content output 
\newcommand{\OneOne}{One One content}
\newcommand{\OneTwo}{One Two content}
\newcommand{\OneThree}{One Three content}
\newcommand{\OneFour}{One Four content}
\newcommand{\OneFive}{One Five content}
\newcommand{\TwoOne}{Two One content}
\newcommand{\TwoTwo}{Two Two content}
% and so on....

%Translator "Switch" statement
\newcommand{\GetNumberText}[1]
{ 
\ifthenelse{\equal{#1}{1}}{One}{}
\ifthenelse{\equal{#1}{2}}{Two}{}
\ifthenelse{\equal{#1}{3}}{Three}{}
\ifthenelse{\equal{#1}{4}}{Four}{}
\ifthenelse{\equal{#1}{5}}{Five}{}
}

%csname macro to assemble the content-containing macro
\newcommand{\AssembleNumCmd}[2]{\csname #1#2\endcsname}

%this does not compile: desired functionality
%\newcommand{\DoContent}[2]{\AssembleNumCmd{\GetNumberText{#1}}{\GetNumberText{#2}}}

%this compiles: literal example
\newcommand{\DoContent}[2]{\AssembleNumCmd{One}{Three}}

\begin{document}

\DoContent{1}{3}

\end{document}

这应该产生

一三内容

看来我不能在 的定义中使用任何条件语句\GetNumberText,并且仍然传递\GetNumberText{1}给。如果我使用我在那里注释\AssembleNumCmd的 版本(这就是我想要做的),则文档不会编译。\DoContent

显然,这是一些有点愚蠢的做法,我愿意接受更好的整体方法。但是,我仍然想知道为什么这种相对简单的方法不起作用,以及如何修复它。

我尝试过\protect在这里和那里使用,并使用不同的“切换”宏来\ifx代替\ifthenelse,以及其他较小的更改,但似乎没有什么可以编译而没有错误(“缺少\endcsname插入”等等)。

这是我使用的问题吗\csname?还是我对宏扩展和脆弱性不够了解?

答案1

这是一个expl3版本,存储One, .... , Ten在一个\clist变量中:

\documentclass[10pt]{article}

\usepackage{xparse}

\newcommand{\OneOne}{One One content}
\newcommand{\OneTwo}{One Two content}
\newcommand{\OneThree}{One Three content}
\newcommand{\OneFour}{One Four content}
\newcommand{\OneFive}{One Five content}
\newcommand{\TwoOne}{Two One content}
\newcommand{\TwoTwo}{Two Two content}
% and so on....

%Translator "Switch" statement



\ExplSyntaxOn
\clist_new:N \g_turanc_numbername_clist
\clist_set:Nn \g_turanc_numbername_clist {One, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten}

\NewDocumentCommand{\GetNumberText}{m}{%
  \clist_item:Nn \g_turanc_numbername_clist {#1}
}
\ExplSyntaxOff



%csname macro to assemble the content-containing macro
\newcommand{\AssembleNumCmd}[2]{\csname #1#2\endcsname}


\newcommand{\DoContent}[2]{\AssembleNumCmd{\GetNumberText{#1}}{\GetNumberText{#2}}}


\begin{document}

\DoContent{1}{3}

\DoContent{2}{2}

\DoContent{1}{5}

\end{document}

在此处输入图片描述

旧版

\ifthenelse用“更简单”的\ifcase ...\or ...\fi语句替换了个别情况的条件。我认为它也可能适用于其他软件包。

\documentclass[10pt]{article}

\usepackage{xifthen}

%End-Content output 
\newcommand{\OneOne}{One One content}
\newcommand{\OneTwo}{One Two content}
\newcommand{\OneThree}{One Three content}
\newcommand{\OneFour}{One Four content}
\newcommand{\OneFive}{One Five content}
\newcommand{\TwoOne}{Two One content}
\newcommand{\TwoTwo}{Two Two content}
% and so on....

%Translator "Switch" statement

\newcommand{\GetNumberText}[1]
{%
  \ifcase #1 
  \or
  One%
  \or
  Two%
  \or
  Three%
  \or
  Four%
  \or
  Five%
  \fi
}


%csname macro to assemble the content-containing macro
\newcommand{\AssembleNumCmd}[2]{\csname #1#2\endcsname}

%This does not compile: desired functionality
\newcommand{\DoContent}[2]{\AssembleNumCmd{\GetNumberText{#1}}{\GetNumberText{#2}}}


%this compiles: literal example
%\newcommand{\DoContent}[2]{\AssembleNumCmd{One}{Three}}

\begin{document}

\DoContent{1}{3}


\DoContent{2}{2}

\DoContent{1}{5}


\end{document}

**\ifx版本:

不能有空格字符,因此测试等时要小心:

\documentclass[10pt]{article}


%End-Content output 
\newcommand{\OneOne}{One One content}
\newcommand{\OneTwo}{One Two content}
\newcommand{\OneThree}{One Three content}
\newcommand{\OneFour}{One Four content}
\newcommand{\OneFive}{One Five content}
\newcommand{\TwoOne}{Two One content}
\newcommand{\TwoTwo}{Two Two content}
% and so on....

%Translator "Switch" statement


\newcommand{\GetNumberText}[1]
{%
  \ifx#11%
  One%
  \else
  \ifx#12%
  Two%
  \else
  \ifx#13%
  Three%
  \else
  \ifx#14%
  Four%
  \else
  \ifx#15%
  Five%
  \fi
  \fi
  \fi
  \fi
  \fi
}



%csname macro to assemble the content-containing macro
\newcommand{\AssembleNumCmd}[2]{%
\csname #1#2\endcsname%
}

\newcommand{\DoContent}[2]{\AssembleNumCmd{\GetNumberText{#1}}{\GetNumberText{#2}}}

\begin{document}

\DoContent{1}{3}

\DoContent{2}{2}

\DoContent{1}{2}

\DoContent{1}{5}

\end{document}

答案2

正如我在评论中所写,使用\ifthenelsein\csname不起作用。

除此之外,你还把事情复杂化了。你已经知道命令名称可以包含字母以外的其他内容,那么为什么不将这些知识用于内容定义呢?

\documentclass[10pt]{article}

\makeatletter
\@namedef{text1-1}{One One content}
\@namedef{test1-2}{One Two content}
\makeatother


\newcommand{\DoContent}[2]{\csname test#1-#2\endcsname}

\begin{document}

\DoContent{1}{2}

\end{document}

在此处输入图片描述

答案3

正如 Ulrike 指出的那样,\ifthenelse不能在中使用\csname...\endcsname,其中只允许使用完全可扩展到字符的宏。

以下是使用 case switch 的不同实现:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\DoContent}{mm}
 {
  \str_case:nnF { #1-#2 }
   {
    {1-1}{One~One~content}
    {1-2}{One~Two~content}
    {1-3}{One~Three~content}
    {1-4}{One~Four~content}
    {1-5}{One~Five~content}
    {2-1}{Two~One~content}
    {2-2}{Two~Two~content}
   }
   {Invalid~choice}
 }
\ExplSyntaxOff

\begin{document}

\DoContent{1}{3}

\end{document}

添加案例的可能更好的界面:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\DoContent}{mm}
 {
  \str_case:nVF { #1-#2 } \g_turanc_choices_tl 
   {Invalid ~ choice}
 }

\NewDocumentCommand{\AddContent}{m}
 {
  \clist_map_inline:nn { #1 }
   {
    \tl_gput_left:Nn \g_turanc_choices_tl { ##1 }
   }
 }

\tl_new:N \g_turanc_choices_tl

\ExplSyntaxOff

\AddContent{
  {1-1}{One One content},
  {1-2}{One Two content},
  {1-3}{One Three content},
  {1-4}{One Four content},
  {1-5}{One Five content},
}

\AddContent{
  {2-1}{Two One content},
}
\AddContent{
  {2-2}{Two Two content},
}

\begin{document}

\DoContent{1}{3}

\DoContent{2}{2}

\DoContent{9}{9}

\end{document}

请注意,\AddContent是累积的​​,因此即使在之后,也可以在需要时添加对\begin{document}。如果您两次添加一对,则最后一次添加的对将\AddContent获胜,因此您以后可以覆盖启动时做出的选择。

在此处输入图片描述

相关内容