8

I want to split a string into individual characters, transform each character individually, then join them back together.

Something like this:

\newcommand{\drawaboxaroundit}[1]{...}
\newcommand{\glue}{+}
\explodethenjoin{abcdef}{\drawaboxaroundit}{\glue}

Glossing over how \drawaboxaroundit might work (it's just for illustration, it's not what I'm really doing), the result for this example would be something like this:

enter image description here

The intention is for \explodethenjoin{abc}{\drawaboxaroundit}{\glue} will expand to

\drawaboxaroundit{a}\glue\drawaboxaroundit{b}\glue\drawaboxaroundit{c}

I nearly have a solution to my problem with this answer (although I know basically nothing about expl so I don't understand how it works) -- this processes each character individually but does not put glue between them.

One approach (which doesn't seem like good design to me) would be to make \drawaboxaroundit aware of its position, i.e. the above abc example would expand to

\drawaboxarounditwrapper{0}{\glue}{a}\drawaboxarounditwrapper{1}{\glue}{b}\drawaboxarounditwrapper{2}{\glue}{c}

with \drawaboxarounditwrapper defined to be something like this

\newcommand{\drawaboxarounditwrapper}[2]{
    \ifthenelse{\equal{#1}{0}}{}{\glue}
    \drawaboxaroundit{#2}
}

Another option would be to split the string into head character and tail string. Something like this

\witheachcharacterinheadandtail{abcdef}{\drawaboxaroundit}{\glue\drawaboxaroundit}

Where \witheachcharacterinheadandtail{abcdef}{\foo}{\bar} expands into

\foo{a}\bar{b}\bar{c}\bar{d}\bar{e}\bar{f}

This second approach seems to be better, but I don't know how to realize either of these approaches, or whether either is a good idea in the first place.

How can I explode-transform-join a string? We can assume the strings in question are ASCII and contain no latex commands, and all strings will contain at least two characters (a tail will always have nonzero length).

2

3 Answers 3

9

enter image description here

\documentclass{article}
\def\xloop#1{\ifx\relax#1\else\xloopbody{#1}\expandafter\xloop\fi}
\newcommand\explodethenjoin[3]%
  {\def\inter{\def\inter{#3}}%
   \def\xloopbody##1{\inter#2{##1}}%
   \xloop#1\relax
  }
\begin{document}
\explodethenjoin{abcdef}{\fbox}{+}
\end{document}

The macro \xloop iterates over the tokens following it until it encounters \relax. It has been used several times on this site. For each token the macro \xloopbody is executed; by defining it appropriately, the tokens can be processed as needed.

6

As TeX doesn't really have strings, you do not need any specific commands to split up a token list, it is already a list of distinct tokens. Similarly you don't have to use an explicit loop macro as iterating over a token list is just the normal tex behaviour.

\documentclass{article}

\def\zz#1{\def\zzsep{}\zzz#1\relax}
\def\zzz#1{\ifx\relax#1\else\zzsep\def\zzsep{+}\fbox{#1}\expandafter\zzz\fi}
\begin{document}
\zz{abcdef}
\end{document}

enter image description here

3
  • Isn't this exactly my solution (except for the wrapper and renaming)? And I'd call \zzz a loop since it calls itself ... Of course, my solution should maybe be better called your solution as the code is attributed to you in one post, or maybe to someone else since similar code appears in various style files and classes.
    – gernot
    Apr 13, 2017 at 11:21
  • @gernot yes more or less, I probably just concentrated on making sure egreg didn't get a tick:-) (didn't notice this comment at the time for some reason) May 27, 2017 at 10:00
  • While two dogs are fighting for a bone, a third runs away with it ;-)
    – gernot
    May 28, 2017 at 9:13
5

It's a breeze with xparse:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\splitstring}{mmO{}}
 {
  \spraff_string_split:nnn { #1 } { #2 } { #3 }
 }

\seq_new:N \l_spraff_string_in_seq
\seq_new:N \l_spraff_string_out_seq

\cs_new_protected:Nn \spraff_string_split:nnn
 {
  % split the string at 'nothing'
  \seq_set_split:Nnn \l_spraff_string_in_seq { } { #1 }
  % change each item into '#2{<item>}'
  \seq_set_map:NNn \l_spraff_string_out_seq \l_spraff_string_in_seq { #2 { ##1 } }
  % use the sequence with '#3' in between items
  \seq_use:Nn \l_spraff_string_out_seq { #3 }
 }
\ExplSyntaxOff

\NewDocumentCommand{\boxit}{m}{\fbox{\strut#1}}

\begin{document}

\splitstring{abcdef}{\boxit}

\splitstring{abcdef}{\boxit}[${}+{}$]

\end{document}

Beware that the macro used as second argument to \splitstring should be defined with \NewDocumentCommand.

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .