Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I'm attempting to create 2 macros to simulate an array list as in Java for example. I'm using xstring StrSubstitute for this purpose, but I'm having a problem. Below is the code, it's a bit long as it contains the macros plus the test document.

The currently active StrSubstitute line is working as it is specifying the recipient of the substitution explicitly (\Cities).

The 1st commented StrSubstitute line (using \csname #1\endcsname) on the other hand causes the following TeX error :

! Extra \endcsname.
<argument> \csname testAL\endcsname 

l.21 \addElementToArrayList{testAL}{Paris}

The 2nd commented line (using just #1) causes the following error:

! Missing control sequence inserted.
<inserted text> 
            \inaccessible 
l.21 \addElementToArrayList{testAL}{Paris}

I tried to read some TeX resources, but I am not able to make it work and I find lots of possibilities (\def, \edef, \noexpand...)

\documentclass[a4paper,10pt]{article}
\usepackage[utf8x]{inputenc}
\RequirePackage{xstring}    %will use this package for the internal list structure

\def\ARRAYENDSENTINEL{@@}   %indicates array end
\def\ARRAYSEPARATOR{,}      %element separator

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Macro to create a new list:
%Parameters: <list name>
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\def\newArrayList#1{%
      \expandafter\def\csname#1\endcsname{\ARRAYENDSENTINEL}
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Macro to append element on a list:
%Parameters: <list name>, <element to add>
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\def\addElementToArrayList#1#2{
  \StrSubstitute[1]{\csname #1\endcsname}{\ARRAYENDSENTINEL}{\ARRAYSEPARATOR #2\ARRAYENDSENTINEL}[\Cities] %working
  %\StrSubstitute[1]{\csname #1\endcsname}{\ARRAYENDSENTINEL}{\ARRAYSEPARATOR #2\ARRAYENDSENTINEL}[\csname #1\endcsname] %NOT working!
  %\StrSubstitute[1]{\csname #1\endcsname}{\ARRAYENDSENTINEL}{\ARRAYSEPARATOR #2\ARRAYENDSENTINEL}[#1] %NOT working either!
}

%opening
\title{Testing ArrayList}
\author{}

\begin{document}
\maketitle

\newArrayList{Cities}

Contents of Cities: \textbf{[\Cities]}

\addElementToArrayList{Cities}{Paris}

Contents of Cities: \textbf{[\Cities]}

\addElementToArrayList{Cities}{London}

Contents of Cities: \textbf{[\Cities]}

\addElementToArrayList{Cities}{Rome}

Contents of Cities: \textbf{[\Cities]}


\end{document}
share|improve this question
    
Please always state the error you get. This can help a lot with tracking down the cause. Just saying "does not work" isn't very helpful. –  Martin Scharrer May 3 '11 at 0:13

1 Answer 1

up vote 5 down vote accepted

You can't use \csname foo\endcsname at locations were \foo is required, e.g. \def\csname foo\endcsname{...} will redefine \csname with foo\endcsname as a parameter text and ... as replacement text. You need to expand \csname foo\endcsname first once to build \foo. The \expandafter primitive helps you here. It expands the token (=~ macro or character) after the following token once. So \expandafter\def\csname foo\endcsname{...} will expand to \def\foo{...} so that \foo is defined. A problem here is that you might need many \expandafter if you want to expand the \csname ...\endcsname at the end of a long line.

In this case it is better to either store the line in a temporary macro:

\def\addElementToArrayList#1#2{%
  \begingroup
  \def\temp{\endgroup\StrSubstitute[1]{\csname #1\endcsname}{\ARRAYENDSENTINEL}{\ARRAYSEPARATOR #2\ARRAYENDSENTINEL}[}%
  \expandafter\temp\csname #1\endcsname]%
}

or by expanding the \csname ...\endcsname first and feeding it to a second macro:

\def\addElementToArrayList#1{%
  \expandafter\addElementToArrayListX\expandafter{\csname #1\endcsname}%
}

\def\addElementToArrayListX#1#2{%
  \StrSubstitute[1]{#1}{\ARRAYENDSENTINEL}{\ARRAYSEPARATOR #2\ARRAYENDSENTINEL}[#1]%
}

Here we use two \expandafters in a row to "jump over" \addElementToArrayListX and {. Note that it is perfectly OK to read the second argument only with the second macro.

share|improve this answer
    
Thanks, both solutions working though seem tricky (too advanced fr me). I updated the question by adding another statement using just #1 without \csname. I wonder why it doesn't work unlike your second solution which seems a little similar. –  John Kirollos May 3 '11 at 10:51
    
@John Kirollos: No, that doesn't work. You might just pass \Cities instead of Cities to your macro, then you can use #1 directly (in both places). –  Martin Scharrer May 3 '11 at 11:00

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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