1

I am trying to read a set of pre-defined data using /csname and /endcsname. However, "missing /endcsname inserted" error keeps appearing. Here is a simplified LaTex code.

\documentclass[11pt, oneside]{article}
\usepackage{geometry}
\geometry{letterpaper}

\def\datahello@zero@string{Hello}
\def\datahello@zero@symbol{, }
\def\datahello@one@string{world}
\def\datahello@one@symbol{!}
\def\datagreeting@zero@string{Nice}
\def\datagreeting@zero@symbol{ }
\def\datagreeting@one@string{to}
\def\datagreeting@one@symbol{ }
\def\datagreeting@two@string{meet}
\def\datagreeting@two@symbol{ }
\def\datagreeting@three@string{you}
\def\datagreeting@three@symbol{.}

\newcommand\digittoliteral[1]{%
    \ifcase#1\relax%
        zero%
        \or one%
        \or two%
        \or three%
        \or four%
        \or five%
        \or six%
        \or seven%
        \or eight%
        \or nine%
        \else #1%
    \fi%
}

\newcommand\literaldataname{}
\def\getdata#1#2#3{%
%   data#1@\digittoliteral{#2}@#3%  % Correctly gives datahello@zero@string
%   \csname #1@\digittoliteral{#2}\endcsname%   % First attempt fails because macro call within csname is illegal?
    \edef\literaldataname{data#1@\digittoliteral{#2}@#3}%   % Expects \literaldataname = dataalpha@zero
    \literaldataname%   % Correctly gives data@zero
    \csname \literaldataname\endcsname% % Second attempt fails?
}

\begin{document}
\getdata{hello}{0}{string}\getdata{hello}{0}{symbol}\getdata{hello}{1}{string}\getdata{hello}{1}{symbol}
\newline
\getdata{greeting}{0}{string}\getdata{greeting}{0}{symbol}\getdata{greeting}{1}{string}\getdata{greeting}{1}{symbol}\getdata{greeting}{2}{string}\getdata{greeting}{2}{symbol}\getdata{greeting}{3}{string}\getdata{greeting}{3}{symbol}
\end{document}

And I keep getting the following error.

Missing \endcsname inserted.
<to be read again>
                   \relax
l.42 alpha: \getdata{hello}{0}{string}
                                      \getdata{hello}{0}{symbol}

I think I need to use \expandafter in the first attempt (somehow). However, I wonder why the second attempt is not working when I think \edef will expand everything?

3
  • 1
    Remove the \relax from \ifcase. A \relax cannot appear in a \csname. Also, you might need a \makeatletter at the beginning. Apr 5, 2020 at 13:58
  • If you are OK with defining your datahello macros with \csname you can even do away with \digittoliteral completely: \expandafter\def\csname datahello@0@string\endcsname{Hello} (untested, so fingers crossed I didn't mess up the \expandafters, edit: of course the first attempt was wrong, corrected). etoolbox can come in very handy here: \csdef{datahello@0@string}{Hello} is a bit easier on the eye, I think.
    – moewe
    Apr 5, 2020 at 14:05
  • Macros in a \csname...\endcsname are perfectly fine, so \csname #1@\digittoliteral{#2}\endcsname would be OK if \digittoliteral behaves properly.
    – moewe
    Apr 5, 2020 at 14:08

1 Answer 1

1

Remove \relax from the definition of \digittoliteral.

\documentclass{article}

\makeatletter
\def\datahello@zero@string{Hello}
\def\datahello@zero@symbol{, }
\def\datahello@one@string{world}
\def\datahello@one@symbol{!}
\def\datagreeting@zero@string{Nice}
\def\datagreeting@zero@symbol{ }
\def\datagreeting@one@string{to}
\def\datagreeting@one@symbol{ }
\def\datagreeting@two@string{meet}
\def\datagreeting@two@symbol{ }
\def\datagreeting@three@string{you}
\def\datagreeting@three@symbol{.}
\makeatother

\newcommand\digittoliteral[1]{%
    \ifcase#1
        zero%
        \or one%
        \or two%
        \or three%
        \or four%
        \or five%
        \or six%
        \or seven%
        \or eight%
        \or nine%
        \else #1%
    \fi
}

\newcommand\literaldataname{}
\def\getdata#1#2#3{\csname data#1@\digittoliteral{#2}@#3\endcsname}

\begin{document}

\getdata{hello}{0}{string}\getdata{hello}{0}{symbol}%
\getdata{hello}{1}{string}\getdata{hello}{1}{symbol}

\getdata{greeting}{0}{string}\getdata{greeting}{0}{symbol}%
\getdata{greeting}{1}{string}\getdata{greeting}{1}{symbol}%
\getdata{greeting}{2}{string}\getdata{greeting}{2}{symbol}%
\getdata{greeting}{3}{string}\getdata{greeting}{3}{symbol}

\end{document}

enter image description here

If you're worried about the unprotected end-of-line, don't be. You might use

\ifcase\numexpr#1\relax

instead, if you plan not to pass only explicit digits to \getdata.

An expl3 implementation, with a somewhat easier syntax for storing data.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\newdata}{mmm}
 {% #1 = name for collection, #2 = subname, #3 = data
  \data_new:nnn { #1 } { #2 } { #3 }
 }
\NewExpandableDocumentCommand{\getdata}{mmm}
 {% #1 = name of collection, #2 = index, #3 = key
  \prop_item:cn {g_data_#1_#3_prop} { #2 }
 }

\seq_new:N \l__data_temp_seq
\cs_generate_variant:Nn \prop_gput:Nnn { cx }

\cs_new_protected:Nn \data_new:nnn
 {
  \prop_new:c {g_data_#1_#2_prop}
  \seq_set_from_clist:Nn \l__data_temp_seq { #3 }
  \seq_indexed_map_inline:Nn \l__data_temp_seq
   {
    \prop_gput:cxn {g_data_#1_#2_prop} { \int_eval:n { ##1 - 1 } } { ##2 }
   }
 }
\ExplSyntaxOff

\newdata{hello}{string}{Hello,world}
\newdata{hello}{symbol}{{, },!}

\newdata{greeting}{string}{Nice,to,meet,you}
\newdata{greeting}{symbol}{{ },{ },{ },{.}}

\begin{document}

\getdata{hello}{0}{string}\getdata{hello}{0}{symbol}%
\getdata{hello}{1}{string}\getdata{hello}{1}{symbol}

\getdata{greeting}{0}{string}\getdata{greeting}{0}{symbol}%
\getdata{greeting}{1}{string}\getdata{greeting}{1}{symbol}%
\getdata{greeting}{2}{string}\getdata{greeting}{2}{symbol}%
\getdata{greeting}{3}{string}\getdata{greeting}{3}{symbol}

\end{document}
1
  • Wow, this problem is solved so easily. Thank you so much for the fix and expl3 usage! I'd better study expl3.
    – user207854
    Apr 8, 2020 at 16:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .