# xstring macros inside foreach

I don't really understand what is the problem here, but I guess it has to do with expansion and fragile macros since when I do the same outside of \path it works.

Code:

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{arrows,calc}
\usepackage{xstring}

\newcommand{\aw}{10pt}
\newcommand{\bbw}{20pt}
\newcommand{\cw}{30pt}

\newcommand{\width}[1]{%
\StrBefore{#1}{'}[\notprimed]
\IfEndWith{#1}{'}
{ \csname \notprimed w\endcsname }
{ \csname #1w\endcsname }
}

\begin{document}

\foreach \name in {a,bb,c,a'}
{ ++(\width{\name},0pt) node {\name} };

\begin{tikzpicture}
% \draw (0pt,0pt) node {s}
%   ++(\aw,0pt) node {a}
%   ++(\bbw,0pt) node {bb}
%   ++(\cw,0pt) node {c}
%   ++(\aw,0pt) node {a'};

\draw (0pt,0pt) node {s}
\foreach \name in {a,bb,c,a'}
{ ++(\width{\name},0pt) node {\name} };
\end{tikzpicture}

\end{document}


I think it has to do with xstring also because when I remove the \StrBefore and \IfEndWith from the definition of \width it also works.

Any ideas?

-
So why don't you just take the first letter no matter what comes in the foreach loop instead of testing for prime? – percusse Mar 24 '13 at 23:49
@percusse Because the name of the macros don't have only one letter in my code and don't have the same length either. In any case, I don't think that would change anything right? (I edited the question to reflect the fact that in my code the macros don't have only one letter and don't have the same length) – Ricardo Mar 24 '13 at 23:59
Welcome to TeX.SE! – cmhughes Mar 25 '13 at 0:29
The problem seems to be in (\width{…},0pt) as \width{…} is not just a length but includes all the xstring stuff, too. You will need to do that outside of the path (or inside of \pgfextra). – Qrrbrbirlbel Mar 25 '13 at 0:33
@Qrrbrbirlbel How can I do it outside of the path? I've been also thinking about that but I have no idea how to do it. – Ricardo Mar 25 '13 at 0:39

You need to move the usage of the xstring macros outside of the coordinates as they are not fully expandable and do not result simply in \csname #1w\endcsname.

With \pgfextra{<stuff>} or \pgfextra <stuff> \endpgfextra you can do <stuff> that does not belong into a path.

It seems to me, you just want to strip a trailing ' from, so you could simply do:

\makeatletter
\newcommand{\width}[1]{%
\StrSubstitute{#1}{'}{}[\qrr@width]%
\expandafter\let\expandafter\widthresult\csname\qrr@width w\endcsname}
\makeatother


and use it in

  \foreach \name in {a,bb,c,a'}{
\pgfextra{\width{\name}}
++ (\widthresult,0pt) node {\name}
}


The following solution strips everything after the first ' and works (due its simplicity) even inside a coordinate.

## Code

\documentclass{article}
\usepackage{tikz}
\newcommand{\aw}{10pt}
\newcommand{\bbw}{20pt}
\newcommand{\cw}{30pt}
\makeatletter
\def\strip@upquote#1'#2\@strip@upquote{#1}
\newcommand{\width}[1]{\csname\expandafter\strip@upquote#1'\@strip@upquote w\endcsname}
\makeatother
\begin{document}
\begin{tikzpicture}
\draw (0pt,0pt) node {s}
\foreach \name in {a,bb,c,a'}{
++ (\width{\name},0pt) node {\name}
};
\end{tikzpicture}
\end{document}

-
What are those \expandafter for? – Ricardo Mar 25 '13 at 1:05
@Ricardo It builds the \csname …\endcsname sequence before \letting it to #2. Otherwise you would try to do \let#2\csname and a trailing <some stuff>\endcsname which will fail. That said, I fear you could optimize your \width code but I do not know your rules for the names and what should taken from it to build \…w. Do you just want to strip any occurrence of '? – Qrrbrbirlbel Mar 25 '13 at 1:35
Yes, that all I need. I know there's only one ' and it's always at the end. – Ricardo Mar 25 '13 at 1:38
@Ricardo I have updated my answer explaining a little bit and added a very basic solution for your use-case. – Qrrbrbirlbel Mar 25 '13 at 1:58