在学习如何使用的过程中\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
正如我在评论中所写,使用\ifthenelse
in\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
获胜,因此您以后可以覆盖启动时做出的选择。