2

In my project, I already have a file containing commands for names of my documents :

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

I've also created a function to obtain the word associated with a number between 1 and 9:

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

(where \ifthenelse and \equal comes from the ifthen package)

This function produce the desired output, for instance when compiling \setIntToString{0}\getIntToString\ \setIntToString{1}\getIntToString in the document, I obtain "wrongInput One" in the pdf.

I would like to write a function like the following:

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

So that \doc\setIntToString{#1}\getIntToString becomes \docOne if I write \docTitle{1}, \docTwo if I write \docTitle{2}, etc.

I guess this has something to do with \csname, \expandafter, \csuse, \@namedef ... but I don't know how to use them.

Here is my 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}
  • You need \csname ... \endcsname. – user156344 May 7 at 15:03
  • I guess, yes, but how? Especially that the desired command names already exist... – Apeiron May 7 at 15:08
0

You might do

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

The group ensures that the redefinition of \getIntToString is forgotten.

enter image description here

Much better with higher level functions.

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

enter image description here

1

Using the \name-macro (see in the example below) you can easily both define and call control-sequence-tokens/macros whose names may also contain digits. These digits then may as well come from the values of counters. Using this technique you are not bound to using digits.

The gist of the \name-macro is: It takes material before the first following opening brace for its first argument and material nested into the first following opening brace and the matching closing brace for its second argument and applies \csname..\endcsname to that second argument while leaving the first argument in place. Hereby the first argument my be empty.

You can do things like
\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}

enter image description here


If you insist in control sequences \docOne, \docTwo, ... instead of \doc1, \doc2, ... , you can still use the \name-macro for creating a generic macro which "maps" from digit sequences to these control-sequences.

In the example below the macro \map has the syntax

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

E.g.,
\map{Foo}{3}{Bar}
checks whether a mapping from the string 3 to some other string is defined.
If not so, an error-message is raised.
If so, and if 3 is mapped to the string Three, it is checked whether the control-sequence \FooThreeBar is defined.
If not so, an error-message is raised.
If so, that control-sequence is called.

The macro \definemapping{⟨string⟩}{⟨replacement⟩} is used for defining the mappings.

E.g., for the above to work, you would need to apply the command \definemapping{3}{Three}% first.

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

enter image description here


Another common strategy is using macro-names which have roman numerals as parts of their names:

\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}
  • This was very enlightning, thank you very much :) – Apeiron May 9 at 6:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.