5

I have a very large number which goes over multiple lines. I want to typeset it in math mode so that it becomes more readable by grouping the digits in blocks of length n.

The answers of this post are not applicable for me because

  • I want to start grouping from the first digits, not from the last (i.e. I want 123 456 7 rather than 1 234 567)
  • I also want the groups to be of other fixed lengths than 3 (i.e. 1234 5678 rather than 12 345 678)

Is there a nice and easy way to achieve this?

EDIT: Thanks to @leandriis I got to this code (taken from here):

\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
}

Which lets me use

\split{4}{12345678}

However, I still need linebreaks to be inserted automatically since my numbers are hundreds of digits long. Maybe it would even be possible to align the digits in the new lines so that all \,-separators are aligned?

Jakob W.
  • 187
  • 1
    Probably interesting: https://tex.stackexchange.com/q/177100/134144 – leandriis Jan 04 '20 at 14:46
  • @leandriis Yes, the answer from user2478 is almost what I need. However I would like to have a generic command $\GroupDigits{5}{number}$ where 5 is my n. I am not very familiar with tex code and my attempts to modify the code failed. – Jakob W. Jan 04 '20 at 15:01
  • 1
    https://tex.stackexchange.com/a/171010/134144 is also similar and might be useful. – leandriis Jan 04 '20 at 15:12
  • @leandriis thanks! this almost soved my problem, but there is one problem left: I need some linebreaks since my numbers are hundreds of digits long. I will update the post with the code I copied. – Jakob W. Jan 04 '20 at 15:20
  • 1
    To get the \split macro to allow line breaks in text mode, just replace \, with \hspace{0.1666em}. For use in math mode, replace \, with \,\allowbreak. – Mico Jan 04 '20 at 16:00

4 Answers4

6

Here's a \groupify command:

\groupify[<sep>]{<n>}{<tokens>}

which will separate the <tokens> in groups of <n> items (starting form the left) and will insert <sep> between each pair of groups. The default <sep> is \,\allowbreak (a thin space which allows a line break).

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewExpandableDocumentCommand \groupify { O{\,\allowbreak} m m }
  { \jakob_groupify:nnn {#1} {#2} {#3} }
\cs_new:Npn \jakob_groupify:nnn #1 #2 #3
  { \__jakob_groupify_loop:nnw { 1 } {#2} #3 \q_recursion_tail {#1} \q_recursion_stop }
\cs_new:Npn \__jakob_groupify_loop:nnw #1 #2 #3
  {
    \quark_if_recursion_tail_stop:n {#3}
    \exp_not:n {#3}
    \int_compare:nNnTF {#1} = {#2}
      { \__jakob_groupify_sep:n }
      { \exp_args:Nf \__jakob_groupify_loop:nnw { \int_eval:n { #1+1 } } }
          {#2}
  }
\cs_new:Npn \__jakob_groupify_sep:n #1 #2 \q_recursion_tail #3
  {
    \tl_if_empty:nF {#2} { \exp_not:n {#3} }
    \__jakob_groupify_loop:nnw { 1 } {#1}
    #2 \q_recursion_tail {#3}
  }
\ExplSyntaxOff
\begin{document}
\groupify{3}{01234567890123456789012345678901234567890123456789}

\groupify[ X ]{5}{01234567890123456789012345678901234567890123456789}
\end{document}
  • Can you modify the code so that automatic line breaking occurs if and when needed? – Mico Jan 04 '20 at 15:34
  • 1
    @Mico Done. Poor choice of default separator ;-) Thanks for the suggestion! – Phelype Oleinik Jan 04 '20 at 15:45
  • Already thanks! This might be a noob question, but I get an "Undefined control sequence" at \NewExpandableDocumentCommand which I could not resolve – Jakob W. Jan 04 '20 at 16:09
  • 2
    @JakobS You have an old TeX distribution, in which \NewExpandableDocumentCommand is not available. You can try replacing that by \NewDocumentCommand, but then you lose expandability (which is not too important here). Which TeX distribution/version do you have? (You can check with tex --version, in a terminal. – Phelype Oleinik Jan 04 '20 at 16:39
  • TeX 3.14159265 (TeX Live 2015/Debian) – Jakob W. Jan 05 '20 at 00:18
  • @JakobS Sorry, I only have TeXLive 2017 onwards to test. But replacing \NewExpandableDocumentCommand by \NewDocumentCommand should work. – Phelype Oleinik Jan 05 '20 at 03:02
  • I have a follow-up question: https://tex.stackexchange.com/questions/523173/how-to-add-overline-for-grouped-and-linebreaked-numbers – cis Jan 06 '20 at 20:25
5

Here's a LuaLaTeX-based solution. It consists of a Lua function called groupnum which does the actual work and a LaTeX macro called \groupnum, which takes two arguments. The first is optional and sets the grouping length; the default length is 4. The second is the number that's supposed to be grouped.

enter image description here

% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{luacode}
\begin{luacode}
function groupnum ( s , n )
   while #s > n do
      tex.sprint ( s:sub(1,n) .. "\\mkern3mu\\allowbreak")
      s = s:sub(n+1) 
   end
   tex.sprint ( s )
end   
\end{luacode}
%% LaTeX utility macro:
\newcommand\groupnum[2][4]{\directlua{groupnum("#2",#1)}}

\begin{document}
\raggedright
$\groupnum{123456789012345}$

$\groupnum[5]{123456789012345}$

$\groupnum[7]{1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890}$
\end{document}
Mico
  • 506,678
0

I can offer a \romannumeral0-expansion-based solution which does not require any ε-TeX-extensions or the like, and where the result is delivered after two expansion-steps/after two hits with \expandafter.

The routine \groupify processes a sequence of non-delimited arguments that should form a sequence of single characters, e.g., digits.

Syntax:

\groupify{&langle;characters/non-delimited arguments to group&rangle;}%
         {&langle;token for formatting a group of characters&rangle;}%
         {&langle;separator-tokens to insert behind a formatted group of characters&rangle;}%
         {&langle;remainder k&rangle;}%
         {&langle;modulus n&rangle;}%

Expansion will not be applied to ⟨characters/non-delimited arguments to group⟩.

The routine works as if you would count the non-delimited arguments/the characters from left to right, beginning with 1.

A new character-group is started after each character whose number is congruent ⟨k⟩ modulo ⟨n⟩.

In case ⟨n⟩ is a non-positive integer number, character-grouping will not take place.

Each group of characters will be nested in curly braces and be lead by ⟨token for formatting a group of characters⟩ and trailed by ⟨separator-tokens to insert behind a formatted group of characters⟩.
The last group of characters will not be trailed by ⟨separator-tokens to insert behind a formatted group of characters⟩.

Both ⟨k⟩ and ⟨n⟩ must be sequences that denote ⟨number⟩-quantities in the sense of the TeXbook. If they are not, all kinds of errors can/will occur. There is no checking/error-catching implemented on that. (Be aware that reliably testing whether an arbitrary token-sequence forms a ⟨number⟩-quantity in the sense of the TeXbook is not feasible. Reason: Arbitrary token-sequences can form arbitrary expansion-based algorithms. One requirement for an arbitrary expansion-based algorithm to form a ⟨number⟩-quantitiy in the sense of the TeXbook is that the algorithm terminates (without errors). Thus such a test requires finding out whether an arbitrary expansion-based algorithm terminates (without errors). Thus the task of implementing such a test implies being faced with the halting-problem. Alan Mathison Turing proved in 1936 that a general algorithm to solve the halting problem for all possible program-input pairs cannot exist.)

\documentclass[a4paper, landscape]{article}

\makeatletter %%----------------------------------------------------------------------------- %% Layout of example document %%----------------------------------------------------------------------------- @ifundefined{pagewidth}{}{\pagewidth=\paperwidth} @ifundefined{pdfpagewidth}{}{\pdfpagewidth=\paperwidth} @ifundefined{pageheight}{}{\pageheight=\paperheight} @ifundefined{pdfpageheight}{}{\pdfpageheight=\paperheight} \textwidth=\paperwidth \oddsidemargin=1.25cm \topmargin=\oddsidemargin \advance\textwidth-2\oddsidemargin \advance\oddsidemargin-1in \evensidemargin=\oddsidemargin \marginparwidth=1.5cm \marginparsep=.5cm \parindent=0ex \parskip=.25\baselineskip \textheight=\paperheight \advance\textheight-2\topmargin \footskip=.5\topmargin \begingroup \normalsize\normalfont\selectfont \advance\footskip.5\ht\strutbox \expandafter\endgroup \expandafter\footskip\expandafter=\the\footskip \begingroup \normalsize\normalfont\selectfont \expandafter\endgroup\expandafter\topskip\expandafter=\the\ht\strutbox \advance\topmargin-1in \headheight=0ex \headsep=0ex \pagestyle{plain}% \makeatother

\makeatletter %%----------------------------------------------------------------------------- %% Code for \groupify %%----------------------------------------------------------------------------- %% Exchange things in the token-stream: %%............................................................................. \newcommand\UD@PassFirstToSecond[2]{#2{#1}}% \newcommand\UD@Exchange[2]{#2#1}% %%----------------------------------------------------------------------------- %% Check whether argument is empty: %%............................................................................. %% \UD@CheckWhetherNull{<Argument which is to be checked>}% %% {<Tokens to be delivered in case that argument %% which is to be checked is empty>}% %% {<Tokens to be delivered in case that argument %% which is to be checked is not empty>}% %% %% The gist of this macro comes from Robert R. Schneck's \ifempty-macro: %% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J> \newcommand\UD@CheckWhetherNull[1]{% \romannumeral0\expandafter@secondoftwo\string{\expandafter @secondoftwo\expandafter{\expandafter{\string#1}\expandafter @secondoftwo\string}\expandafter@firstoftwo\expandafter{\expandafter @secondoftwo\string}@firstoftwo\expandafter{} @secondoftwo}% {@firstoftwo\expandafter{} @firstoftwo}% }% %%----------------------------------------------------------------------------- %% Check whether argument is blank (empty or only spaces): %%----------------------------------------------------------------------------- %% -- Take advantage of the fact that TeX discards space tokens when %% "fetching" _un_delimited arguments: -- %% \UD@CheckWhetherBlank{<Argument which is to be checked>}% %% {<Tokens to be delivered in case that %% argument which is to be checked is blank>}% %% {<Tokens to be delivered in case that argument %% which is to be checked is not blank>}% \newcommand\UD@CheckWhetherBlank[1]{% \romannumeral\expandafter\expandafter\expandafter@secondoftwo \expandafter\UD@CheckWhetherNull\expandafter{@firstoftwo#1{}.}% }% %%----------------------------------------------------------------------------- %% Extract first inner undelimited argument: %% \UD@ExtractFirstArg{ABCDE} yields A %% \UD@ExtractFirstArg{{AB}CDE} yields AB %%----------------------------------------------------------------------------- \newcommand\UD@RemoveTillUD@SelDOm{}% \long\def\UD@RemoveTillUD@SelDOm#1#2\UD@SelDOm{{#1}}% \newcommand\UD@ExtractFirstArg[1]{% \romannumeral0% \UD@ExtractFirstArgLoop{#1\UD@SelDOm}% }% \newcommand\UD@ExtractFirstArgLoop[1]{% \expandafter\UD@CheckWhetherNull\expandafter{@firstoftwo{}#1}% {@firstoftwo\expandafter{} @secondoftwo{}#1}% {\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillUD@SelDOm#1}}% }% %%----------------------------------------------------------------------------- \newcommand\groupify[5]{% % #1 = characters to group % #2 = tokens for formatting a group of characters % #3 = separator-tokens to insert behind a group of characters if the number % denoting the position of the current character is congruent k modulo n % #4 = remainder k % #5 = modulus n \romannumeral0% \expandafter\UD@CheckWhetherNull\expandafter{\romannumeral#5}{% \groupifynormalizeloop{#1}{#2}{}% }{% \expandafter\UD@CheckWhetherNull\expandafter{\romannumeral#4}{% \expandafter\UD@CheckWhetherNull\expandafter{\romannumeral-\number#4}{% \expandafter\UD@PassFirstToSecond\expandafter{\romannumeral\number\number#5 000}{% \expandafter\UD@PassFirstToSecond\expandafter{\romannumeral\number\number#5 000}{% \expandafter\UD@PassFirstToSecond\expandafter{\romannumeral\number\number#5 000}{% \expandafter\UD@PassFirstToSecond\expandafter{\romannumeral\number\number#5 000}{% \preparegroupifyloop }% }% }% }% {@firstoftwo}% }{% \expandafter\UD@PassFirstToSecond\expandafter{\romannumeral\number\number#5 000}{% \expandafter\UD@PassFirstToSecond\expandafter{\romannumeral\number-\number#4 000}{% \expandafter\UD@PassFirstToSecond\expandafter{\romannumeral\number\number#5 000}{% \expandafter\UD@PassFirstToSecond\expandafter{\romannumeral\number-\number#4 000}{% \preparegroupifyloop }% }% }% }% {@secondoftwo}% }% }{% \expandafter\UD@PassFirstToSecond\expandafter{\romannumeral\number\number#5 000}{% \expandafter\UD@PassFirstToSecond\expandafter{\romannumeral\number\number#4 000}{% \expandafter\UD@PassFirstToSecond\expandafter{\romannumeral\number\number#5 000}{% \expandafter\UD@PassFirstToSecond\expandafter{\romannumeral\number\number#4 000}{% \preparegroupifyloop }% }% }% }% {@firstoftwo}% }% {#1}{{#2}{#3}}{@firstoftwo}% }% }% \newcommand\preparegroupifyloop[8]{% #8{% %#1 = characters m in the amount of remainder k %#2 = characters m in the amount of modulus n %#3 = characters m in the amount of remainder k %#4 = characters m in the amount of modulus n %#5 = positive/negative remainder @firstoftwo/@secondoftwo %#6 = number to group %#7 = formatting-tokens/separator-tokens %#8 = stage of loop / @firstoftwo/@secondoftwo \UD@CheckWhetherNull{#1}{% \UD@CheckWhetherNull{#2}{% \groupifyloop{#4}{#4}{#4}{#4}{#6}{#7}{}{@firstoftwo}{}% }{% #5{% \preparegroupifyloop{}{#2}{#4}{#4}{}{#6}{#7}{@secondoftwo}% }{% \groupifyloop{#2}{#4}{#2}{#4}{#6}{#7}{}{@firstoftwo}{}% }% }% }{% \UD@CheckWhetherNull{#2}{% \expandafter\UD@PassFirstToSecond\expandafter{@gobble#4}% }{% \expandafter\UD@PassFirstToSecond\expandafter{@gobble#2}% }% {% \expandafter\preparegroupifyloop\expandafter{@gobble#1}% }{#3}{#4}{#5}{#6}{#7}{#8}% }% }{% %#1 = empty/not needed in this stage %#2 = remainder of the modulus %#3 = difference between remainder of the modulus and modulus %#4 = characters m in the amount of modulus n %#5 = empty/not needed in this stage %#6 = number to group %#7 = formatting-tokens/separator-tokens %#8 = stage of loop / @secondoftwo \UD@CheckWhetherNull{#2}{% \groupifyloop{#3}{#4}{#3}{#4}{#6}{#7}{}{@firstoftwo}{}% }{% \expandafter\UD@PassFirstToSecond\expandafter{@gobble#3}{% \expandafter\UD@PassFirstToSecond\expandafter{@gobble#2}{\preparegroupifyloop{}}% }{#4}{#5}{#6}{#7}{#8}% }% }% }% \newcommand\groupifyloop[9]{% % #1 = remainder % #2 = module % #3 = remainder % #4 = module % #5 = characters to group % #6 = formatting-tokens/separator-tokens % #7 = characters grouped so far % #8 = indicator whether on start of interval (@firstoftwo) or not (@secondoftwo) % #9 = group collected so far \UD@CheckWhetherBlank{#5}{% \UD@CheckWhetherNull{#9}{ #7}{% \expandafter\UD@CheckWhetherNull\expandafter{@firstoftwo#6}% {\UD@Exchange}{\UD@PassFirstToSecond}{#9}{% \expandafter\UD@Exchange\expandafter{@firstoftwo#6}{% \UD@CheckWhetherNull{#7}{ }{% \expandafter\UD@Exchange\expandafter{@secondoftwo#6}{ #7}% }% }% }% }% }{% \expandafter\UD@PassFirstToSecond\expandafter{% \romannumeral0% \expandafter\expandafter\expandafter\UD@Exchange\expandafter\expandafter\expandafter{% \UD@ExtractFirstArg{#5}% }{% \UD@CheckWhetherNull{#1}{#8{ }{ #9}}{ #9}% }% }{% \UD@CheckWhetherNull{#1}{% \UD@CheckWhetherNull{#2}{% \UD@PassFirstToSecond{@firstoftwo}% }{% \UD@PassFirstToSecond{@secondoftwo}% }% }{% \UD@CheckWhetherNull{#2}{% \UD@PassFirstToSecond{@firstoftwo}% }{% \UD@PassFirstToSecond{#8}% }% }% {% \expandafter\UD@PassFirstToSecond\expandafter{% \romannumeral0% \UD@CheckWhetherNull{#1}{#8{@secondoftwo}{@firstoftwo}}{@firstoftwo}% { #7}% {% \expandafter\UD@CheckWhetherNull\expandafter{@firstoftwo#6}% {\UD@Exchange}{\UD@PassFirstToSecond}{#9}{% \expandafter\UD@Exchange\expandafter{% @firstoftwo#6% }{% \UD@CheckWhetherNull{#7}{ }{% \expandafter\UD@Exchange\expandafter{% @secondoftwo#6% }{ #7}% }% }% }% }% }% {% \UD@PassFirstToSecond{#6}{% \expandafter\UD@PassFirstToSecond\expandafter{@gobble#5}{% \UD@Exchange{{#3}{#4}}{% \UD@CheckWhetherNull{#2}{% \expandafter\UD@PassFirstToSecond\expandafter{@gobble#4}% {\expandafter\UD@PassFirstToSecond\expandafter{@gobble#3}{\groupifyloop}}% }{% \expandafter\UD@PassFirstToSecond\expandafter{@gobble#2}% {% \UD@CheckWhetherNull{#1}{% \groupifyloop{}% }{% \expandafter\groupifyloop\expandafter{@gobble#1}% }% }% }% }% }% }% }% }% }% }% }% \newcommand\groupifynormalizeloop[3]{% % #1 = characters to group % #2 = tokens for formatting a group of characters % #3 = sequence normalized so far \UD@CheckWhetherBlank{#1}{ #2{#3}}{% \expandafter\UD@PassFirstToSecond\expandafter{% \romannumeral0% \expandafter\expandafter\expandafter\UD@Exchange \expandafter\expandafter\expandafter{\UD@ExtractFirstArg{#1}}{ #3}% }{% \expandafter\groupifynormalizeloop\expandafter{@gobble#1}{#2}% }% }% }% %%----------------------------------------------------------------------------- %% End of code for \groupify %%----------------------------------------------------------------------------- \makeatother

\begin{document}

\begin{tabular}{|lll|}% \hline \textbf{\LaTeX-code:}&$\to$&\textbf{Result:}\\hline \verb|A\groupify{123 4 51 2 3 4 5 1 2 345123}{\textbf}{,\allowbreak}{3}{0}B|&$\to$& A\groupify{123 4 51 2 3 4 5 1 2 345123}{\textbf}{,\allowbreak}{3}{0}B\ \verb|A\groupify{123451234512345123}{\textbf}{,\allowbreak}{-5}{5}B|&$\to$& A\groupify{123451234512345123}{\textbf}{,\allowbreak}{-5}{5}B\ \verb|A\groupify{123451234512345123}{\textbf}{,\allowbreak}{-4}{5}B|&$\to$& A\groupify{123451234512345123}{\textbf}{,\allowbreak}{-4}{5}B\ \verb|A\groupify{123451234512345123}{\textbf}{,\allowbreak}{-3}{5}B|&$\to$& A\groupify{123451234512345123}{\textbf}{,\allowbreak}{-3}{5}B\ \verb|A\groupify{123451234512345123}{\textbf}{,\allowbreak}{-2}{5}B|&$\to$& A\groupify{123451234512345123}{\textbf}{,\allowbreak}{-2}{5}B\ \verb|A\groupify{123451234512345123}{\textbf}{,\allowbreak}{-1}{5}B|&$\to$& A\groupify{123451234512345123}{\textbf}{,\allowbreak}{-1}{5}B\ \verb|A\groupify{123451234512345123}{\textbf}{,\allowbreak}{0}{5}B|&$\to$& A\groupify{123451234512345123}{\textbf}{,\allowbreak}{0}{5}B\ \verb|A\groupify{123451234512345123}{\textbf}{,\allowbreak}{1}{5}B|&$\to$& A\groupify{123451234512345123}{\textbf}{,\allowbreak}{1}{5}B\ \verb|A\groupify{123451234512345123}{\textbf}{,\allowbreak}{2}{5}B|&$\to$& A\groupify{123451234512345123}{\textbf}{,\allowbreak}{2}{5}B\ \verb|A\groupify{123451234512345123}{\textbf}{,\allowbreak}{3}{5}B|&$\to$& A\groupify{123451234512345123}{\textbf}{,\allowbreak}{3}{5}B\ \verb|A\groupify{123451234512345123}{\textbf}{,\allowbreak}{4}{5}B|&$\to$& A\groupify{123451234512345123}{\textbf}{,\allowbreak}{4}{5}B\ \verb|A\groupify{123451234512345123}{\textbf}{,\allowbreak}{5}{5}B|&$\to$& A\groupify{123451234512345123}{\textbf}{,\allowbreak}{5}{5}B\ \verb|A\groupify{123451234512345123}{\textbf}{,\allowbreak}{6}{5}B|&$\to$& A\groupify{123451234512345123}{\textbf}{,\allowbreak}{6}{5}B\ \hline \end{tabular}%

\vfill

\verb|\groupify| requires two expansion-steps/two hits'' by \verb|\expandafter| to deliver the result---\verb|\testdefiner|hits'' \verb|\groupify| by \verb|\expandafter| twice before defining \verb|\test|:

\vfill

\newcommand\testdefiner[1]{% \expandafter\expandafter\expandafter\gdef \expandafter\expandafter\expandafter\test \expandafter\expandafter\expandafter{% \expandafter\expandafter\expandafter A% #1% B}% }%

\newcommand\showtest{% $\to$ \texttt{\string\test\ \meaning\test}% }%

\begin{tabular}{|l|}% \hline \verb|\testdefiner{\groupify{123 4 51 2 3 4 5 1 2 345123}{\textbf}{,\allowbreak}{3}{0}}|% \testdefiner{\groupify{123 4 51 2 3 4 5 1 2 345123}{\textbf}{,\allowbreak}{3}{0}}\ \showtest\ \hline \verb|\testdefiner{\groupify{123451234512345123}{\textbf}{,\allowbreak}{-5}{5}}|% \testdefiner{\groupify{123451234512345123}{\textbf}{,\allowbreak}{-5}{5}}\ \showtest\ \hline \verb|\testdefiner{\groupify{123451234512345123}{\textbf}{,\allowbreak}{-4}{5}}|% \testdefiner{\groupify{123451234512345123}{\textbf}{,\allowbreak}{-4}{5}}\ \showtest\ \hline \verb|\testdefiner{\groupify{123451234512345123}{\textbf}{,\allowbreak}{-3}{5}}|% \testdefiner{\groupify{123451234512345123}{\textbf}{,\allowbreak}{-3}{5}}\ \showtest\ \hline \verb|\testdefiner{\groupify{123451234512345123}{\textbf}{,\allowbreak}{-2}{5}}|% \testdefiner{\groupify{123451234512345123}{\textbf}{,\allowbreak}{-2}{5}}\ \showtest\ \hline \verb|\testdefiner{\groupify{123451234512345123}{\textbf}{,\allowbreak}{-1}{5}}|% \testdefiner{\groupify{123451234512345123}{\textbf}{,\allowbreak}{-1}{5}}\ \showtest\ \hline \verb|\testdefiner{\groupify{123451234512345123}{\textbf}{,\allowbreak}{0}{5}}|% \testdefiner{\groupify{123451234512345123}{\textbf}{,\allowbreak}{0}{5}}\ \showtest\ \hline \verb|\testdefiner{\groupify{123451234512345123}{\textbf}{,\allowbreak}{1}{5}}|% \testdefiner{\groupify{123451234512345123}{\textbf}{,\allowbreak}{1}{5}}\ \showtest\ \hline \verb|\testdefiner{\groupify{123451234512345123}{\textbf}{,\allowbreak}{2}{5}}|% \testdefiner{\groupify{123451234512345123}{\textbf}{,\allowbreak}{2}{5}}\ \showtest\ \hline \verb|\testdefiner{\groupify{123451234512345123}{\textbf}{,\allowbreak}{3}{5}}|% \testdefiner{\groupify{123451234512345123}{\textbf}{,\allowbreak}{3}{5}}\ \showtest\ \hline \verb|\testdefiner{\groupify{123451234512345123}{\textbf}{,\allowbreak}{4}{5}}|% \testdefiner{\groupify{123451234512345123}{\textbf}{,\allowbreak}{4}{5}}\ \showtest\ \hline \verb|\testdefiner{\groupify{123451234512345123}{\textbf}{,\allowbreak}{5}{5}}|% \testdefiner{\groupify{123451234512345123}{\textbf}{,\allowbreak}{5}{5}}\ \showtest\ \hline \verb|\testdefiner{\groupify{123451234512345123}{\textbf}{,\allowbreak}{6}{5}}|% \testdefiner{\groupify{123451234512345123}{\textbf}{,\allowbreak}{6}{5}}\ \showtest\ \hline \end{tabular}

\newpage

\newlength\chunkwidth \newcommand\chunkbox[1]{% \ifvmode \sloppy\leavevmode \hbox to\chunkwidth{\hfil$#1$}% \else \hbox to\chunkwidth{$#1$\hfil}% \fi }%

\newcommand\ChunkGroupifyParagraph[4]{% \begingroup \par \settowidth\chunkwidth{#1}% \groupify{#2}{\chunkbox}{\thinspace\allowbreak}{#3}{#4}% \par \endgroup }%

\ChunkGroupifyParagraph {12345}{% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% }{2}{5}%

\bigskip

\ChunkGroupifyParagraph {12345678}{% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% }{3}{8}%

\bigskip

\ChunkGroupifyParagraph {000}{% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% 12345123451234512345123451234512345123451234512345% }{0}{3}%

\end{document}

enter image description here enter image description here

user202729
  • 7,143
Ulrich Diez
  • 28,770
0

A simpler routine that can be better understood:

\documentclass{article}

\ExplSyntaxOn

\NewDocumentCommand{\printlargenumber}{O{3}m} { \jakob_largenumber_print:nn { #1 } { #2 } }

\seq_new:N \l__jakob_largenumber_input_seq

\cs_new_protected:Nn \jakob_largenumber_print:nn { \seq_set_split:Nnn \l__jakob_largenumber_input_seq { } { #2 } \seq_indexed_map_inline:Nn \l__jakob_largenumber_input_seq { ##2 % the current digit \int_compare:nT { \int_mod:nn { ##1 } { #1 } = 0 } { \hspace{0.16667em ~ plus 0.16667em ~ minus 0.08333em} } } }

\ExplSyntaxOff

\begin{document}

\printlargenumber{ 01234567890123456789012345678901234567890123456789 01234567890123456789012345678901234567890123456789 01234567890123456789012345678901234567890123456789 01234567890123456789012345678901234567890123456789 01234567890123456789012345678901234567890123456789 01234567890123456789012345678901234567890123456789 01234567890123456789012345678901234567890123456789 }

\printlargenumber[6]{ 01234567890123456789012345678901234567890123456789 01234567890123456789012345678901234567890123456789 01234567890123456789012345678901234567890123456789 01234567890123456789012345678901234567890123456789 01234567890123456789012345678901234567890123456789 01234567890123456789012345678901234567890123456789 01234567890123456789012345678901234567890123456789 }

\end{document}

The argument is split at “nothing” and doing so spaces get ignored, so this eases input as you don't need to worry about endlines. After that a loop over the sequence is started; if we have done as many steps as stated in the optional argument (default 3), a flexible space is added, to help with justification.

enter image description here

egreg
  • 1,121,712