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 want a macro that somehow replaces whitespace (spaces, newlines, tabs?) from the start of a string.

Something like

mystring.replace(/^\s*/g, "")

in JavaScript.

Is that possible?

share|improve this question
1  
the stringstrings package has a macro \removeleadingspaces[mode]{string}. Whether this is applicable for you will strongly depend on whether the argument you pass to the macro is pure text or has embedded macros. –  Steven B. Segletes Jun 2 at 11:51
    
@StevenB.Segletes : This is what I have been looking for. Submit it as answer and I will accept it. –  Karel Bílek Jun 2 at 12:03

2 Answers 2

up vote 6 down vote accepted

Expandable, infinite spaces

Removing space tokens at the begin of a string is possible, but a little cumbersome:

\documentclass{article}

\makeatletter
\let\TrSp@X\relax
\let\TrSp@Y\relax
\edef\TrSp@XSpXNil{%
  \TrSp@X\space\TrSp@X
  \noexpand\noexpand\noexpand\TrSp@NIL
}
\long\edef\trim@pre@spaces#1{%
  \noexpand\romannumeral0%
  \noexpand\TrSp@pre@spaces\TrSp@X#1\TrSp@Y\TrSp@XSpXNil
}
\@firstofone{\long\def\TrSp@pre@spaces#1\TrSp@X} %
#2\TrSp@X#3\TrSp@NIL{%
  \csname TrSp@pre#3\endcsname{#1}{#2}%
}
\long\def\TrSp@pre#1#2{%
  \expandafter
  \TrSp@pre@\expandafter\space\@gobble#1%
}
\long\def\TrSp@pre@#1\TrSp@Y{#1}
\long\expandafter\edef\csname TrSp@pre X\endcsname#1#2{%
  \noexpand\TrSp@pre@spaces\TrSp@X#2\TrSp@XSpXNil
}
\def\TrSp@X{X}
\let\TrSp@Y\TrSp@NIL
\let\trimstartspaces\trim@pre@spaces
\newcommand*{\trimstartspacesin}[1]{%
  \expandafter\expandafter\expandafter\expandafter
  \expandafter\expandafter\expandafter\def
  \expandafter\expandafter\expandafter\expandafter
  \expandafter\expandafter\expandafter#1%
  \expandafter\expandafter\expandafter\expandafter
  \expandafter\expandafter\expandafter{%
    \expandafter\trimstartspaces\expandafter{\foo}%
  }%
}
\makeatother


% create a text with several spaces in a row using a trick:
\newcommand*{\deffoo}[1]{%
  \newcommand*{\foo}{#1#1#1#1a b c }%
}
\deffoo{ }
\let\trimmedfoo\foo
\trimstartspacesin\trimmedfoo

\typeout{[\expandafter\trimstartspaces\expandafter{\foo}]}
\typeout{[\trimmedfoo]}

\begin{document}
[\foo] $\rightarrow$ [\expandafter\trimstartspaces\expandafter{\foo}]
  or [\trimmedfoo]
\end{document}

Result

Expandable, at most one space

Package trimspaces already provides \trim@pre@space or \trim@pre@space@in.

Manually it can be done by

\romannumeral-`\.

\romannumeral applied to negative numbers vanishes and TeX keeps looking for an optional space after the character constant `\..

If the text is inside a macro \foo, then an optional space can be stripped at the beginning by:

\expandafter\def\expandafter\foo\expandafter{%
  \romannumeral-\expandafter`\expandafter\.\foo
}%

Full example:

\documentclass{article}
\newcommand*{\foo}{ a b c }
\expandafter\def\expandafter\trimmedfoo\expandafter{%
  \romannumeral-\expandafter`\expandafter\.\foo
}%
\typeout{[\meaning\trimmedfoo]}

\begin{document}
[\foo] $\rightarrow$ [\trimmedfoo]
\end{document}

Result

Usually removing one optional space is enough, because it is not too easy entering more than one space in a row (TeX collapses them to one space during tokenizing).

Non-expandable, infinite spaces

\@ifnextchar removes spaces before testing the "next" character. In non expandable contexts it can be used to remove infinite spaces from the begin of the text:

\documentclass{article}

% create a text with several spaces in a row using a trick:
\newcommand*{\deffoo}[1]{%
  \newcommand*{\foo}{#1#1#1#1a b c }%
}
\deffoo{ }

\makeatletter
\newcommand*{\stripstartspaces}{%
  \expandafter\@ifnextchar\expandafter X\expandafter{\expandafter
  }\expandafter{\expandafter}%
}
\makeatother

\begin{document}
[\foo] $\rightarrow$ [\stripstartspaces\foo]
\end{document}

Result

share|improve this answer
    
This strips at most one space token. –  egreg Jun 2 at 12:16
    
@egreg: I have now added expandable and non-expandable methods for stripping infinite space tokens at the begin. –  Heiko Oberdiek Jun 2 at 12:48
1  
I knew this would have triggered some nice code from you. +1! –  egreg Jun 2 at 12:55
    
\stripstartspaces works perfectly for my case. Thanks, accepting. –  Karel Bílek Jun 2 at 14:27

The stringstrings package has a \removeleadingspaces macro, which will remove any combination of blanks and hard spaces at the the beginning of the passed text string. The package is generally intended to operate only upon text strings, and has only a very limited ability (not shown in this answer) to handle arguments containing macros.

By default, the macro will output the result immediately to the screen. However, if the processed but unprinted result is desired, a [q] optional argument will instead put the result in \thestring via an \edef for later access. There is also an [e] "encoded" mode, which applies if one is trying to process strings containing a limited number of user-predefined macros (but that's for a different question).

\documentclass{article}
\usepackage{stringstrings}
\begin{document}
.\removeleadingspaces{abc def}

.\removeleadingspaces{ abc def}

.\removeleadingspaces{  abc def}

.\removeleadingspaces{~abc def}

.\removeleadingspaces{~~abc def}

.\removeleadingspaces{~ ~ abc def}

.\removeleadingspaces{~ ~ abc def}
\end{document}

enter image description here

share|improve this answer
    
I originally wanted to accept your answer. However, \removeleadingspaces started to make some problems with "forced" breaking words with \-, which for unknown reasons started to expand as ....... \stripstartspaces from the other answer works better, I am sorry :) –  Karel Bílek Jun 2 at 14:26
1  
@KarelBílek Go with the best answer. I know that stringstrings suffers severe limitations. I'm glad you found an answer that works for you. –  Steven B. Segletes Jun 2 at 14:33

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.