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 need to split a string into one or more substrings. I know that I could use the xstring package, but I'd like to do it using only inbuilt TeX/LaTeX commands. So, if I say

\def\MyTeXKnowledge{Not good enough}

what is the simplest way to extract the substrings "Not", "good" and "enough" from the macro \MyTexKnowledge and store them in variables?

share|improve this question

2 Answers 2

up vote 23 down vote accepted

You need to define a macro which has the separation character in the parameter text:

\def\testthreewords#1{\threewords#1\relax}
\def\threewords#1 #2 #3\relax{ First: (#1), Second: (#2), Third: (#3) }
\testthreeowords{Now good enough}

If you want to be able to provide a macro as argument you need to expand it first. This can be either done once (only first macro is expanded once):

\def\testthreewords#1{\expandafter\threewords#1\relax}

or completely:

\def\testthreewords#1{%
    \begingroup
    \edef\@tempa{#1}%
    \expandafter\endgroup
    \expandafter\threewords\@tempa\relax
}

The \relax here is used as an end marker and must not occur in the argument, otherwise a different macro should be used, like \@nnil. The grouping is added to keep the temporary definitions local.

However this setup fails with an error if the two spaces are not included in the argument. To be on the safe side you should read every substring on its own and add the separation character to the end as a fail-safe. Then you test if the end was reached:

\def\testwords#1{%
    \begingroup
    \edef\@tempa{#1\space}%
    \expandafter\endgroup
    \expandafter\readwords\@tempa\relax
}
\def\readwords#1 #2\relax{%
      \doword{#1}%  #1 = substr, #2 = rest of string
      \begingroup
      \ifx\relax#2\relax  % is #2 empty?
         \def\next{\endgroup\endtestwords}% your own end-macro if required
      \else
         \def\next{\endgroup\readwords#2\relax}%
      \fi
      \next
}
\def\doword#1{(#1)}
\def\endtestwords{}


\testwords{Now good enough}% Gives `(Now)(good)(enough)`
\testwords{Now good}% Gives `(Now)(good)`
share|improve this answer
    
thanks. With your help I have achieved the result that I needed. I think a modification is needed before I accept your answer, though. If I define \MyTeXKnowledge as above and then say \testthreewords{\MyTeXKnowledge} I get an error (presumably because \MyTeXKnowledge counts as only one argument). –  Ian Thompson Mar 6 '11 at 22:49
    
@Ian: I wasn't sure about the exact interface you want to use. You need to expand the macro first. I will update my answer. –  Martin Scharrer Mar 6 '11 at 22:53
1  
I have edited the wording of my question to clarify. –  Ian Thompson Mar 6 '11 at 23:09

Another way : the words are stocked in macros \worda \wordb etc.

\documentclass[a4paper]{article}  

\newcount\nbofwords
\makeatletter  
\def\myutil@empty{}
\def\multiwords#1 #2\@nil{% 
 \def\NextArg{#2}%
 \advance\nbofwords by  1 %   
 \expandafter\edef\csname word\@alph\nbofwords\endcsname{#1}% 
 \ifx\myutil@empty\NextArg
     \let\next\@gobble
 \fi
 \next#2\@nil
}%    

\def\GetWords#1{%
   \let\next\multiwords 
   \nbofwords=0 %
   \expandafter\next#1 \@nil %
}% 
\makeatother

\begin{document}
 \def\MyTeXKnowledge{Not good  enough the end}
\GetWords{\MyTeXKnowledge}

There are \the\nbofwords\  words:  \worda; \wordb; \wordc;\wordd;\worde.

\end{document} 

Now \MyTeXKnowledgeis accepted.

share|improve this answer
    
@Ian: Now \MyTeXKnowledgeis accepted and the substrings from the macro \MyTexKnowledge are stored in variables. –  Alain Matthes Mar 7 '11 at 7:48
    
another nice solution. Thanks. –  Ian Thompson Mar 8 '11 at 23:31
    
@AlainMatthes: I really like this solution since we can use it for an arbitrary number of words, right? I'm just learning TeX but will try to understand better this code since it appears to solve some other question I posted. –  Sergio Parreiras May 12 at 15:58

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.