如何使用字符串组成现有命令的名称?

如何使用字符串组成现有命令的名称?

在我的项目中,我已经有一个包含我的文档名称命令的文件:

\newcommand{\docOne}{Title of my first document}
\newcommand{\docTwo}{Title of my second document}
...

我还创建了一个函数来获取与 1 到 9 之间的数字相关的单词:

\newcommand{\getIntToString}{wrongInput}
\newcommand{\setIntToString}[1]{%
    \ifthenelse{\equal{#1}{1}}{\renewcommand{\getIntToString}{One}}{}%
    \ifthenelse{\equal{#1}{2}}{\renewcommand{\getIntToString}{Two}}{}%
    ...
}

(其中\ifthenelse\equal来自于如果那么包裹)

此函数产生所需的输出,例如 \setIntToString{0}\getIntToString\ \setIntToString{1}\getIntToString 在文档中编译时,我在 pdf 中获得“wrongInput One”。

我想编写如下函数:

\newcommand{\docTitle}[1]{%
    \doc\setIntToString{#1}\getIntToString%
}

所以那就\doc\setIntToString{#1}\getIntToString变成了\docOne如果我写\docTitle{1}\docTwo如果我写\docTitle{2},等等。

\csname我猜这与、、、...有关\expandafter,但我不知道如何使用它们。\csuse\@namedef

这是我的 MWE:

\documentclass{report}
\usepackage{ifthen}

\newcommand{\docOne}{Title of my first document}
\newcommand{\docTwo}{Title of my second document}

\newcommand{\getIntToString}{wrongInput}
\newcommand{\setIntToString}[1]{%
    \ifthenelse{\equal{#1}{1}}{\renewcommand{\getIntToString}{One}}{}%
    \ifthenelse{\equal{#1}{2}}{\renewcommand{\getIntToString}{Two}}{}%
    \ifthenelse{\equal{#1}{3}}{\renewcommand{\getIntToString}{Three}}{}%
    \ifthenelse{\equal{#1}{4}}{\renewcommand{\getIntToString}{Four}}{}%
    \ifthenelse{\equal{#1}{5}}{\renewcommand{\getIntToString}{Five}}{}%
    \ifthenelse{\equal{#1}{6}}{\renewcommand{\getIntToString}{Six}}{}%
    \ifthenelse{\equal{#1}{7}}{\renewcommand{\getIntToString}{Seven}}{}%
    \ifthenelse{\equal{#1}{8}}{\renewcommand{\getIntToString}{Eight}}{}%
    \ifthenelse{\equal{#1}{9}}{\renewcommand{\getIntToString}{Nine}}{}%
}

\newcommand{\docTitle}[1]{%
    \doc\setIntToString{#1}\getIntToString%
}

\begin{document}

\setIntToString{0}\getIntToString\ \setIntToString{1}\getIntToString

%\docTitle{1}, \docTitle{2}

\end{document}

答案1

你可能会

\documentclass{report}
\usepackage{ifthen}

\newcommand{\docOne}{Title of my first document}
\newcommand{\docTwo}{Title of my second document}

\newcommand{\getIntToString}{wrongInput}
\newcommand{\setIntToString}[1]{%
    \ifthenelse{\equal{#1}{1}}{\renewcommand{\getIntToString}{One}}{}%
    \ifthenelse{\equal{#1}{2}}{\renewcommand{\getIntToString}{Two}}{}%
    \ifthenelse{\equal{#1}{3}}{\renewcommand{\getIntToString}{Three}}{}%
    \ifthenelse{\equal{#1}{4}}{\renewcommand{\getIntToString}{Four}}{}%
    \ifthenelse{\equal{#1}{5}}{\renewcommand{\getIntToString}{Five}}{}%
    \ifthenelse{\equal{#1}{6}}{\renewcommand{\getIntToString}{Six}}{}%
    \ifthenelse{\equal{#1}{7}}{\renewcommand{\getIntToString}{Seven}}{}%
    \ifthenelse{\equal{#1}{8}}{\renewcommand{\getIntToString}{Eight}}{}%
    \ifthenelse{\equal{#1}{9}}{\renewcommand{\getIntToString}{Nine}}{}%
}

\newcommand{\docTitle}[1]{%
  \begingroup\setIntToString{#1}%
  \expandafter\endgroup
  \csname doc\getIntToString\endcsname
}

\begin{document}

\setIntToString{0}\getIntToString\ \setIntToString{1}\getIntToString

\docTitle{1}, \docTitle{2}               

\end{document}

该组织确保的重新定义\getIntToString被遗忘。

在此处输入图片描述

更高级别的功能会更好。

\documentclass{report}
\usepackage{xparse}

\ExplSyntaxOn
\cs_new:Nn \apeiron_int_to_string:n
 {
  \int_case:nnF { #1 }
   {
    {1}{One}
    {2}{Two}
    {3}{Three}
    {4}{Four}
    {5}{Five}
    {6}{Six}
    {7}{Seven}
    {8}{Eight}
    {9}{Nine}
   }
   {WrongInput}
 }

\NewDocumentCommand{\docTitle}{m}
 {
  \use:c { doc \apeiron_int_to_string:n { #1 } }
 }
\ExplSyntaxOff

\newcommand{\docOne}{Title of my first document}
\newcommand{\docTwo}{Title of my second document}

\newcommand{\docWrongInput}{WRONG}

\begin{document}

\docTitle{1}, \docTitle{2}, \docTitle{42}

\end{document}

在此处输入图片描述

答案2

使用\name-macro(见下面的示例),您可以轻松定义和调用控制序列标记/宏,其名称也可能包含数字。这些数字也可能来自计数器的值。使用此技术,您不必一定要使用数字。

宏的要点\name是:它需要材料第一个以下的开括号为其第一个参数和材料嵌套到第一个接下来的左括号和与之匹配的右括号第二个论点并应用于\csname..\endcsname第二个参数,同时保留第一个参数。因此第一个参数可能为空。

您可以执行以下操作:
\name\newcommand{foo}...\newcommand\foo...
\name\newcommand{foo}[1]{...}\newcommand\foo[1]{...}
\name\global\long\def{foo}...\global\long\def\foo...
\name{foo}...\foo...
\name\string{foo}...\string\foo...
\name\expandafter{foo}...\expandafter\foo...
\name\name\expandafter{foo}{bar}\expandafter\foo\bar
\name\name\let{foo}={bar}\let\foo=\bar

\documentclass{article}

\newcommand\exchange[2]{#2#1}%
\newcommand\name{}\long\def\name#1#{\romannumeral0\innername{#1}}%
\newcommand\innername[2]{\expandafter\exchange\expandafter{\csname#2\endcsname}{ #1}}%
\newcommand\checkwhethernameundefined{}\name\global\let\checkwhethernameundefined={@ifundefined}%

% let's define the macros \doc1, \doc2, ... , \doc12, and \docWeird:
\name\newcommand{doc1}{Title of my first document}
\name\newcommand{doc2}{Title of my second document}
\name\newcommand{doc3}{Title of my third document}
\name\newcommand{doc4}{Title of my fourth document}
\name\newcommand{doc5}{Title of my fifth document}
\name\newcommand{doc6}{Title of my sixth document}
\name\newcommand{doc7}{Title of my seventh document}
\name\newcommand{doc8}{Title of my eighth document}
\name\newcommand{doc9}{Title of my nineth document}
\name\newcommand{doc10}{Title of my tenth document}
\name\newcommand{doc11}{Title of my eleventh document}
\name\newcommand{doc12}{Title of my twelveth document}
\name\newcommand{docWeird}{Title of my weird document}

% let's define a macro for calling these macros:
\newcommand{\docTitle}[1]{%
  \checkwhethernameundefined{doc#1}{%
    \begingroup
    \def\mytempa{#1}\name{@onelevel@sanitize}\mytempa
    \name{@latex@error}%
         {\string\docTitle{\mytempa} not available:\MessageBreak
          Command \name\string{doc\mytempa} undefined}%
         {Use \string\docTitle\space with number in argument in range from 1 to 12 or with\MessageBreak
          the string "Weird".}%
    \endgroup
  }{%
     \name{doc#1}%
  }%
}%

\begin{document}

\noindent
\verb|\docTitle{1}|: \docTitle{1}\\
\verb|\docTitle{2}|: \docTitle{2}\\
\verb|\docTitle{3}|: \docTitle{3}\\
\verb|\docTitle{4}|: \docTitle{4}\\
\verb|\docTitle{5}|: \docTitle{5}\\
\verb|\docTitle{6}|: \docTitle{6}\\
\verb|\docTitle{7}|: \docTitle{7}\\
\verb|\docTitle{8}|: \docTitle{8}\\
\verb|\docTitle{9}|: \docTitle{9}\\
\verb|\docTitle{10}|: \docTitle{10}\\
\verb|\docTitle{11}|: \docTitle{11}\\
%
% You can also obtain the thing depending on the value stored in a count-register/a LaTeX counter:
\newcounter{docnumber}%
\setcounter{docnumber}{12}%
Counter \verb|docnumber|'s current value is: \number\value{docnumber}\\
\verb|\docTitle{\number\value{docnumber}}|: \docTitle{\number\value{docnumber}}\\
%
% You are not bound to numbers:
% You can define and use macros with almost arbitrary strings in their names:
\verb|\docTitle{Weird}|: \docTitle{Weird}\\
%
% This yields an error-message as \doc13 is undefined:
% \verb|\docTitle{13}|: \docTitle{13}\\

\end{document}

在此处输入图片描述


如果您坚持使用控制序列\docOne, \docTwo, ... 而不是\doc1, \doc2, ... ,您仍然可以使用 -macro\name来创建一个通用宏,将数字序列“映射”到这些控制序列。

在下面的例子中,宏\map的语法如下

\map{⟨macro-name-part before the string which is to be mapped to another string⟩}%
    {⟨string which is to be mapped to another string⟩}%
    {⟨macro-name-part behind the string which is to be mapped to another string⟩}

例如,
\map{Foo}{3}{Bar}
检查是否定义了从字符串3到其他字符串的映射。
如果没有,则引发错误消息。
如果是,并且如果3映射到字符串Three,则检查控制序列是否\FooThreeBar已定义。
如果没有,则引发错误消息。
如果是,则调用该控制序列。

该宏用于定义映射。 \definemapping{⟨string⟩}{⟨replacement⟩}

例如,要使上述操作有效,您需要\definemapping{3}{Three}%先应用该命令。

\documentclass{article}

\newcommand\exchange[2]{#2#1}%
\newcommand\name{}\long\def\name#1#{\romannumeral0\innername{#1}}%
\newcommand\innername[2]{\expandafter\exchange\expandafter{\csname#2\endcsname}{ #1}}%
\newcommand\checkwhethernameundefined{}\name\global\let\checkwhethernameundefined={@ifundefined}%

\newcommand*\Mappinglist{}%

\newcommand\map[3]{%
  \checkwhethernameundefined{my-map-phrase-#2}{%
    \begingroup
    \def\mytempa{#2}\name{@onelevel@sanitize}\mytempa
    \name{@latex@error}{%
      Cannot map from string `\mytempa' to textual phrase:\MessageBreak
      Macro \name\string{my-map-phrase-\mytempa} undefined
    }{Mapping is defined for the string(s) \MessageBreak\Mappinglist.\MessageBreak
      You can use \string\definemapping\space for defining more mappings.
    }%
    \endgroup
  }{%
    \checkwhethernameundefined{#1\name{my-map-phrase-#2}#3}{%
      \begingroup
      \def\mytempa{#1}\name{@onelevel@sanitize}\mytempa
      \def\mytempb{#3}\name{@onelevel@sanitize}\mytempb
      \name{@latex@error}{%
        Control sequence \name\string{\mytempa\name{my-map-phrase-#2}\mytempb} undefined%
      }{%
        Seems the control sequence \name\string{\mytempa\name{my-map-phrase-#2}\mytempb} needs to be defined.%
      }%
      \endgroup
    }{%
      \name{#1\name{my-map-phrase-#2}#3}%
    }%
  }%
}%

\newcommand\definemapping[2]{%
  \checkwhethernameundefined{my-map-phrase-#1}{%
    \name\newcommand{my-map-phrase-#1}{#2}%
    \name\name\global\let{my-map-phrase-#1}={my-map-phrase-#1}%
    \ifx\Mappinglist\empty\else\name{g@addto@macro}\Mappinglist{, }\fi
    \begingroup
    \def\mytempa{`#1'}\name{@onelevel@sanitize}\mytempa  
    \name\expandafter\endgroup\expandafter{g@addto@macro}\expandafter\Mappinglist\expandafter{\mytempa}%
  }{%
    \begingroup
    \def\mytempa{#1}\name{@onelevel@sanitize}\mytempa
    \name{@latex@error}{%
      Mapping for string `\mytempa'\space already defined%
    }{%
      Each string can have only one mapping.\MessageBreak
      Mappings are already defined for the following strings:\MessageBreak
      \Mappinglist.%
    }%
    \endgroup
  }%
}%

\definemapping{1}{One}%
%\definemapping{1}{Uno}% <- This will raise an error-message.
\definemapping{2}{Two}%
\definemapping{3}{Three}%
\definemapping{4}{Four}%
\definemapping{5}{Five}%
\definemapping{6}{Six}%
\definemapping{7}{Seven}%
\definemapping{8}{Eight}%
\definemapping{9}{Nine}%
\definemapping{10}{Ten}%
\definemapping{11}{Eleven}%
\definemapping{12}{Twelve}%
\definemapping{13}{Thirteen}%
\definemapping{Weird}{Weird}%

% let's define the macros \docOne, \docTwo, ... , \docTwelve and \docWeird:
\newcommand{\docOne}{Title of my first document}
\newcommand{\docTwo}{Title of my second document}
\newcommand{\docThree}{Title of my third document}
\newcommand{\docFour}{Title of my fourth document}
\newcommand{\docFive}{Title of my fifth document}
\newcommand{\docSix}{Title of my sixth document}
\newcommand{\docSeven}{Title of my seventh document}
\newcommand{\docEight}{Title of my eighth document}
\newcommand{\docNine}{Title of my nineth document}
\newcommand{\docTen}{Title of my tenth document}
\newcommand{\docEleven}{Title of my eleventh document}
\newcommand{\docTwelve}{Title of my twelveth document}
\newcommand{\docWeird}{Title of my weird document}

% let's define a macro for calling these macros:
\newcommand{\docTitle}[1]{\map{doc}{#1}{}}%

\begin{document}

\noindent
\verb|\docTitle{1}|: \docTitle{1}\\
\verb|\docTitle{2}|: \docTitle{2}\\
\verb|\docTitle{3}|: \docTitle{3}\\
\verb|\docTitle{4}|: \docTitle{4}\\
\verb|\docTitle{5}|: \docTitle{5}\\
\verb|\docTitle{6}|: \docTitle{6}\\
\verb|\docTitle{7}|: \docTitle{7}\\
\verb|\docTitle{8}|: \docTitle{8}\\
\verb|\docTitle{9}|: \docTitle{9}\\
\verb|\docTitle{10}|: \docTitle{10}\\
\verb|\docTitle{11}|: \docTitle{11}\\
%
% You can also obtain the thing depending on the value stored in a count-register/a LaTeX counter:
\newcounter{docnumber}%
\setcounter{docnumber}{12}%
Counter \verb|docnumber|'s current value is: \number\value{docnumber}\\
\verb|\docTitle{\number\value{docnumber}}|: \docTitle{\number\value{docnumber}}\\
%
% You are not bound to numbers:
% You can define and use macros with almost arbitrary strings in their names:
\verb|\docTitle{Weird}|: \docTitle{Weird}\\
%
% This yields an error-message as \docThirteen is undefined:
%\verb|\docTitle{13}|: \docTitle{13}\\
%
% This yields an error-message as mapping from 14 to phrase is undefined:
%\verb|\docTitle{14}|: \docTitle{14}\\

\end{document}

在此处输入图片描述


另一种常见的策略是使用以罗马数字作为名称一部分的宏名称:

\documentclass{article}

% let's define the macros \doci, \docii, ... , \docxii:
\newcommand{\doci}{Title of my first document}
\newcommand{\docii}{Title of my second document}
\newcommand{\dociii}{Title of my third document}
\newcommand{\dociv}{Title of my fourth document}
\newcommand{\docv}{Title of my fifth document}
\newcommand{\docvi}{Title of my sixth document}
\newcommand{\docvii}{Title of my seventh document}
\newcommand{\docviii}{Title of my eighth document}
\newcommand{\docix}{Title of my nineth document}
\newcommand{\docx}{Title of my tenth document}
\newcommand{\docxi}{Title of my eleventh document}
\newcommand{\docxii}{Title of my twelveth document}

% let's define a macro for calling these macros:
\makeatletter
\newcommand{\docTitle}[1]{%
  \@ifundefined{doc\romannumeral0#1}{%
    \begingroup
    \def\mytempa{#1}\@onelevel@sanitize\mytempa      
    \expandafter\def\expandafter\mytempb\expandafter{\romannumeral0#1}%
    \@onelevel@sanitize\mytempb
    \@latex@error
       {\string\docTitle{\mytempa} not available:\MessageBreak
        Command \expandafter\string\csname doc\mytempb\endcsname\space undefined}%
       {Use \string\docTitle\space with number in argument in range from 1 to 12.}%
    \endgroup
  }{%
     \csname doc\romannumeral0#1\endcsname
  }%
}%
\makeatother

\begin{document}

\noindent
\verb|\docTitle{1}|: \docTitle{1}\\
\verb|\docTitle{2}|: \docTitle{2}\\
\verb|\docTitle{3}|: \docTitle{3}\\
\verb|\docTitle{4}|: \docTitle{4}\\
\verb|\docTitle{5}|: \docTitle{5}\\
\verb|\docTitle{6}|: \docTitle{6}\\
\verb|\docTitle{7}|: \docTitle{7}\\
\verb|\docTitle{8}|: \docTitle{8}\\
\verb|\docTitle{9}|: \docTitle{9}\\
\verb|\docTitle{10}|: \docTitle{10}\\
\verb|\docTitle{11}|: \docTitle{11}\\
%
% You can also obtain the thing depending on the value stored in a count-register/a LaTeX counter:
\newcounter{docnumber}%
\setcounter{docnumber}{12}%
Counter \verb|docnumber|'s current value is: \number\value{docnumber}\\
\verb|\docTitle{\number\value{docnumber}}|: \docTitle{\number\value{docnumber}}\\
%
% This yields an error-message as \docxiii is undefined:
%\verb|\docTitle{13}|: \docTitle{13}\\

\end{document}

相关内容