5

Is there a neat way to remove all instances of the text \mypath../ from the input, using TeX's text processing capabilities? The ifthen approach below works, but seems to be a bit heavyweight. Also, I'm looking for a solution that would work before the \documentclass command:

\documentclass{scrartcl}
\usepackage{ifthen}

\newcommand{\mypath}[3]{%
  \ifthenelse{\equal{#1#2#3}{../}}{}{#1#2#3}%
}

\begin{document}
  Gobble: \mypath../

  Don't gobble: \mypath.ab
\end{document}
krlmlr
  • 12,530

1 Answers1

7

Here's an expandable way:

\long\def\mypath#1#2#3{\mypathaux../#1#2#3../}
\long\def\mypathaux../#1../{%
  \if\relax\detokenize{#1}\relax
    \expandafter\mypathgobble
  \else
    #1
  \fi}
\long\def\mypathgobble#1#2#3{}

The macro \mypath absorbes the next three tokens and calls \mypathaux in a curious way; let's see the two main cases:

  1. \mypath../ becomes \mypathaux../../../

  2. \mypath xyz becomes \mypathaux../xyz../

The macro \mypathaux has only one argument, all tokens that go from the first occurrence of ../ to the second occurrence. In case 1 there's nothing between the two occurrences, so #1 is empty. In case 2, #1 is xyz.

The macro now tests whether #1 is empty (it's a slick trick by H. Oberdiek); if it is, it calls \mypathgobble that swallows the ../ that remain on the main token list; otherwise it just returns #1.

A similar way that gets rid also of the \fi after #1, which might be needed in some situations is

\makeatletter
\newcommand\mypath[3]{\@mypath../#1#2#3../}
\long\def\@mypath../#1../{%
  \if\relax\detokenize{#1}\relax
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi\@gobblethree{#1}}
\providecommand\@gobblethree[3]{}
\makeatother

This uses features from the LaTeX kernel, while the former macros don't.

Let's see the two cases. With \mypath xyz we get

\@mypath../xyz../

and the test returns false, so we're left with

\expandafter\@secondoftwo\fi\@gobblethree{xyz}

where \expandafter acts on \fi (it simply disappears), leaving

\@secondoftwo\@gobblethree{xyz}

so \@secondoftwo finally produces xyz. In the case of \mypath../ we get

\@mypath../../../

and the test returns true; this leaves

\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi\@gobblethree{}../

(only the first two ../ disappear as part of the pattern matching). The first \expandafter acts on \else which causes everything up to the matching \fi to disappear:

\@firstoftwo\@gobblethree{}../

and now we get

\@gobblethree../

which leaves nothing.

egreg
  • 1,121,712
  • Thank you for your edits. Still, I wonder what happens to the third ../ in \mypath../--> \@mypath../../../ after it has been matched to \@mypath../../ with #1 empty. – krlmlr Sep 11 '12 at 04:49
  • @user946850 In the case you mention, the first pair of ../ disappears as part of the action of \@mypath and the third because \@gobblethree is called. I'll add something. – egreg Sep 11 '12 at 07:37
  • That makes it perfectly clear. Here's the link to the question/answer that explains \expandafter: http://tex.stackexchange.com/q/451/8057 – krlmlr Sep 11 '12 at 11:41