4

Problem

I am trying to split some numbers based on some very simple criteria. Numbers with 8 digits starting with 4, 8 or 9 should be split into digit groups of length 3 2 3.

Any other digit of length 8 should be split into groups of two.

Numbers with less digits than 8 should not be split into groups.

Examples

  • 23 27 60 11 (hard spaces)
  • 404 43 033 (hard spaces, 3 2 3)
  • 820 43 033 (hard spaces, 3 2 3)
  • 909 64 159 (hard spaces)
  • 07979 (no spaces)
  • 110 (no spaces), 112 (no spaces), 113 (no spaces)

Sorry for the lack of MWE, but I am not quite sure where to start.

  • What about numbers with more than 8 digits? – Marijn Aug 13 at 12:15
7

This can be done with the xstring package, which provides commands for extracting and comparing substrings.

It is possible to do some preprocessing to the string before the formatting is applied, for example to remove whitespace. The xstring commands for extracting substrings, modifications and counts have the general syntax \Command{arg1}{...}[\result] where the optional \result argument stores the result for further processing (if this argument is not given the result is just printed directly). This can be used for preprocessing to store the preprocessed string and do the rest of the processing on the result string.

MWE:

\documentclass{article}
\newif\ifstartnum
\usepackage{xstring}
\newcommand{\splitdigits}[1]{%
\StrDel{#1}{ }[\newstring]%
\StrLen{\newstring}[\mylen]%
\ifnum \mylen=8 %
\startnumfalse%
\IfBeginWith{\newstring}{4}{\startnumtrue}{}%
\IfBeginWith{\newstring}{8}{\startnumtrue}{}%
\IfBeginWith{\newstring}{9}{\startnumtrue}{}%
\ifstartnum%
\StrLeft{\newstring}{3}\ \StrMid{\newstring}{4}{5}\ \StrRight{\newstring}{3}%
\else%
\StrLeft{\newstring}{2}\ \StrMid{\newstring}{3}{4}\ \StrMid{\newstring}{5}{6}\ \StrRight{\newstring}{2}%
\fi%
\else%
#1%
\fi%
}
\begin{document}
\noindent\splitdigits{23276011}\\
\splitdigits{40443033}\\
\splitdigits{82043033}\\
\splitdigits{90964159}\\
\splitdigits{07979}\\
\splitdigits{110} \splitdigits{112} \splitdigits{113}\\
\splitdigits{9 09 6415 9}\\
\splitdigits{90 96 41 59}\\
\splitdigits{232 76 011}
\end{document}

Result:

enter image description here

  • Great answer! Is it possible to also handle inputs such at \splitdigits{9 09 6415 9} and \splitdigits{90 96 41 59}, \splitdigits{232 76 011}? – N3buchadnezzar Aug 13 at 15:57
  • @N3buchadnezzar that is possible, you can delete all spaces before you format the numbers using \StrDel. See page 8 of the manual. – Marijn Aug 13 at 16:10
  • @Marjin Thanks! But I still can not make it work. Writing \def\newnum{\StrDel{400 7519}{ }} \newnum \splitdigits{\newnum} Does not work as it expands too late. – N3buchadnezzar Aug 13 at 16:38
  • @N3buchadnezzar the idea is to do the preprocessing inside of the command, see edit. – Marijn Aug 13 at 17:02
  • Thanks a lot, I tried to do as you did but with \newcommand{\newstring}[1]{\StrDel{#1}{ }} is the problem with this approach that the result expands too late? – N3buchadnezzar Aug 13 at 17:19
2

Branch according to the length of the argument: if it is eight digit long, branch with respect to the first digit; otherwise print the argument.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewExpandableDocumentCommand{\phone}{m}
 {
  \nebu_phone:n { #1 }
 }

\cs_new:Nn \nebu_phone:n
 {
  \int_compare:nTF { \tl_count:n { #1 } = 8 }
   {
    \__nebu_phone_eight:n { #1 }
   }
   {
    #1
   }
 }

\cs_new:Nn \__nebu_phone_eight:n
 {
  \str_case_e:nnF { \tl_head:n { #1 } }
   {
    {4}{ \__nebu_phone_iii_ii_iii:nnnnnnnn #1 }
    {8}{ \__nebu_phone_iii_ii_iii:nnnnnnnn #1 }
    {9}{ \__nebu_phone_iii_ii_iii:nnnnnnnn #1 }
   }
   {
    \__nebu_phone_ii:nnnnnnnn #1
   }
 }

\cs_new:Nn \__nebu_phone_iii_ii_iii:nnnnnnnn { #1#2#3\nobreakspace#4#5\nobreakspace#6#7#8 }
\cs_new:Nn \__nebu_phone_ii:nnnnnnnn { #1#2\nobreakspace#3#4\nobreakspace#5#6\nobreakspace#7#8 }

\ExplSyntaxOff

\begin{document}

\phone{23276011}

\phone{40443033}

\phone{82043033}

\phone{90964159}

\phone{07979}

\phone{110}, \phone{112}, \phone{113}

\end{document}

enter image description here

If you want to remove spaces from the input, you have to give up expandability:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\phone}{m}
 {
  \nebu_phone:n { #1 }
 }

\tl_new:N \l__nebu_phone_tl

\cs_new_protected:Nn \nebu_phone:n
 {
  \tl_set:Nn \l__nebu_phone_tl { #1 }
  \tl_remove_all:Nn \l__nebu_phone_tl { ~ }
  \int_compare:nTF { \tl_count:N \l__nebu_phone_tl = 8 }
   {
    \__nebu_phone_eight:V \l__nebu_phone_tl
   }
   {
    \tl_use:N \l__nebu_phone_tl
   }
 }

\cs_new:Nn \__nebu_phone_eight:n
 {
  \str_case_e:nnF { \tl_head:n { #1 } }
   {
    {4}{ \__nebu_phone_iii_ii_iii:nnnnnnnn #1 }
    {8}{ \__nebu_phone_iii_ii_iii:nnnnnnnn #1 }
    {9}{ \__nebu_phone_iii_ii_iii:nnnnnnnn #1 }
   }
   {
    \__nebu_phone_ii:nnnnnnnn #1
   }
 }
\cs_generate_variant:Nn \__nebu_phone_eight:n { V }

\cs_new:Nn \__nebu_phone_iii_ii_iii:nnnnnnnn { #1#2#3\nobreakspace#4#5\nobreakspace#6#7#8 }
\cs_new:Nn \__nebu_phone_ii:nnnnnnnn { #1#2\nobreakspace#3#4\nobreakspace#5#6\nobreakspace#7#8 }

\ExplSyntaxOff

\begin{document}

\phone{232 76 011}

\phone{40 44 30 33}

\phone{820 430 33}

\phone{90964159}

\phone{079 79}

\phone{110}, \phone{112}, \phone{113}

\end{document}

The output is the same.

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.