9

I want to split a character string n by n. I know how to do that 1 by 1 :

\documentclass{article}
\makeatletter

\def\s@plit<#1#2>{%
  \ifx\empty#2%
    #1%
  \else
    #1,\s@plit<#2>%
  \fi}

\def\Split#1#2{\s@plit<#2\empty>}
\makeatother

\begin{document}
\Split{1}{123456789}
\end{document}

It gives : 1,2,3,4,5,6,7,8,9

But I also want 1,23,45,67,89 or 123,456,789 ... depending from the first parameter.

EDIT

Work straight and reverse, even with foreach.

enter image description here

    \documentclass{article}
    \usepackage{tikz,xparse,xstring}

\DeclareDocumentCommand{\split}{smmo}{%
    \xdef\Entree{#3}%
    \let\Sortie\empty%
    \IfBooleanTF #1
    {% sans étoile
        \loop
        \StrRight{\Entree}{#2}[\tmp]%
        \edef\Sortie{\Sortie,\tmp}%
        \StrGobbleRight{\Entree}{#2}[\Entree]%
        \unless\ifx\Entree\empty
        \repeat
        \StrGobbleLeft{\Sortie}{1}[\Sortie]%
    }
    {% avec étoile dans l'ordre inverse
        \loop
        \StrRight{\Entree}{#2}[\tmp]%
        \edef\Sortie{\tmp,\Sortie}%
        \StrGobbleRight{\Entree}{#2}[\Entree]%
        \unless\ifx\Entree\empty
        \repeat
        \StrGobbleRight{\Sortie}{1}[\Sortie]%
    }
    \IfNoValueTF{#4}{\Sortie}{\edef#4{\Sortie}}
    }

\begin{document}
\split{2}{6513782}

\split*{2}{6513782}

\split*{2}{6513782}[\bob]

\foreach \x in \bob {[\x] }

\end{document}
6

This is a job for regular expressions:

\documentclass{article}
\usepackage{xparse,l3regex}

\ExplSyntaxOn
\NewDocumentCommand{\Split}{ m m o }
 {
  \tarass_split:nn { #1 } { #2 }
  \IfNoValueTF { #3 } { \tl_use:N } { \tl_set_eq:NN #3 } \l_tarass_string_tl
 }

\tl_new:N \l_tarass_string_tl

\cs_new_protected:Npn \tarass_split:nn #1 #2
 {
  \tl_set:Nn \l_tarass_string_tl { #2 }
  % we need to start from the end, so we reverse the string
  \tl_reverse:N \l_tarass_string_tl
  % add a comma after any group of #1 tokens
  \regex_replace_all:nnN { (.{#1}) } { \1\, } \l_tarass_string_tl
  % if the length of the string is a multiple of #1 a trailing comma is added
  % so we remove it
  \regex_replace_once:nnN { \,\Z } { } \l_tarass_string_tl
  % reverse back
  \tl_reverse:N \l_tarass_string_tl
 }
\ExplSyntaxOff

\begin{document}

\Split{1}{123456789}

\Split{2}{123456789}

\Split{3}{123456789}[\temp]

\temp

\end{document}

The trailing optional argument is xstring style: if it's specified, then the result is put into that control sequence.

enter image description here

  • I agree it is a job for a regular expression, but I did know that such a package exists. Thanks! – Tarass Apr 11 '14 at 21:19
  • If \Split is used in math mode, what needs to be done so that the commas are treated as having type math-ord rather than math-punct? – Mico Jan 27 '18 at 14:31
  • 1
    @Mico The simplest way is to change \1\, into \1\c{ordinarycomma} with \newcommand{\ordinarycomma}{{,}} in the preamble. – egreg Jan 27 '18 at 14:33
7

The \StrSplit macro from the xstring package may help:

\documentclass{article}
\usepackage{xstring}
\def\split#1#2{%
    \StrSplit{#2}{#1}\tempa\tempb
    \tempa\let\tempa\empty
    \unless\ifx\tempb\empty\def\tempa{,\split{#1}\tempb}\fi
    \tempa
}
\begin{document}
\split{1}{1234567890}

EDIT : This code split from last char to first

\documentclass{article}
\usepackage{xstring}
\def\split#1#2{%
    \def\splitstring{#2}\let\splitresult\empty
    \loop
    \StrLen\splitstring[\tempa]%
    \StrSplit\splitstring{\number\numexpr\tempa-#1}\splitstring\tempb
    \edef\splitresult{\unless\ifx\splitstring\empty,\fi\tempb\splitresult}%
    \unless\ifx\splitstring\empty
    \repeat
    \splitresult
}
\begin{document}
\split{1}{1234567890}

\split{2}{1234567890}

\split{3}{1234567890}

\split{4}{1234567890}
\end{document}
  • I thought about that macro, but I don't know how to have 1,234,567,890 instead of 123,456,789,0 ? – Tarass Apr 11 '14 at 21:08
  • Dégouté sur ce coup. Comme souvent ici... – unbonpetit Apr 11 '14 at 21:32
  • On risque une punition à parler français ;-) Pourquoi dégoûté ? Elle était bien ta solution, il ne restait plus qu'à retourner le sens de lecture. Ce qui génial ici c'est qu'il y a des gens très pointus dans plein de domaines et tu apprends à chaque fois quelque chose: ce coup-ci c'est le package pour les expressions régulières, c'est super utile. – Tarass Apr 11 '14 at 21:43
  • Je me fiche des punitions sur ce site comme de ma première sucette. Dégouté parce que lorsque tu chercheras une solution pour quelqu'un et que tu verras qu'il en a (trop vite) accepté une autre et que la tienne en devient inutile et que tu as cherché pour que dalle, tu sauras pourquoi on peut être dégouté. Voilà. Aller, la punition, maintenant. – unbonpetit Apr 11 '14 at 21:50
  • J'ai ajouté un point à ta réponse, elle n'était pas complète, donc pas acceptable. Il y a des gens ici qui donnent les réponses en 5 minutes parce qu'ils maîtrisent vraiment les outils. Egreg à presque 100 fois plus de points que toi et toi 3 fois plus que moi. Si cela ne t'amuse pas de résoudre le casse-tête, pourquoi y passer tant de temps, qu'elle récompense peut-on espérer à par le plaisir de trouver, d'apprendre et de rendre service. Encore une fois merci. – Tarass Apr 11 '14 at 21:58
2

Here's a LuaLaTeX-based solution. It defines a Lua function called strcomma, which uses Lua's built-in functions string.len and string.sub along with a while .. do .. end loop.

The LaTeX macro \Split is set up as a "wrapper" that invokes strcomma. Note that \Split may be used in both text and math mode -- care is taken so that, if TeX is in math mode, the commas are treated as being of type math-ord, not math-punct.

enter image description here

% !TEX TS-program = lualatex

\documentclass{article}
\directlua{function strcomma ( n , s )
  t = ""
  while string.len ( s ) > n do
    t =  "{,}" .. string.sub ( s, -n ) .. t
    s = string.sub ( s , 1, -n-1 ) 
  end
  t = s .. t
  tex.sprint ( t )
end}
\newcommand\Split[2]{\directlua{strcomma(#1,"#2")}}

\begin{document}
\Split{1}{1234}

$\Split{3}{1234567890}$
\end{document}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.