11

The current default digit grouping option in the package siunitx gives me a large number comma-separated or space-separated every 3 digits, e.g.

\documentclass{article}

\usepackage[utf8]{inputenc}
\usepackage{siunitx}

\begin{document}

   \num[group-separator={,}]{123456789}

\end{document}

would give me 123,456,789. Is it possible to change it so that I get 1,2345,6789?

I can't find an answer in the siunitx documentation or elsewhere on the Internet. I am also happy to know if there is an alternative package that handles number formatting and typesetting automatically just like siunitx, but allows this re-grouping. Thanks in advance!

11
  • 'No' ... not sure that is really an answer!
    – Joseph Wright
    Feb 11, 2018 at 14:00
  • 1
    Welcome to TeX.SX! I don't think it's possible with the current version of siunitx.
    – egreg
    Feb 11, 2018 at 14:03
  • 1
    Can you point to a place where such grouping is used? I can only think of something like credit card numbers, which is well out-of-scope.
    – Joseph Wright
    Feb 11, 2018 at 14:05
  • 1
    Yes, in Chinese and Japanese languages, large numbers are usually multiples of 10,000 rather than 10^3.
    – MikeW
    Feb 11, 2018 at 14:06
  • 1
    related question: tex.stackexchange.com/a/145000/36296 Feb 11, 2018 at 14:26

2 Answers 2

11

There's currently no support for this in siunitx. You can do it with some different code:

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

\ExplSyntaxOn

\NewDocumentCommand{\groupfour}{O{,}m}
 {
  \mikew_groupfour:nn { #1 } { #2 }
 }

\tl_new:N \l_mikew_groupfour_separator_tl
\tl_new:N \l_mikew_groupfour_number_tl

\cs_new_protected:Nn \mikew_groupfour:nn
 {
  \tl_set:Nn \l_mikew_groupfour_separator_tl { {#1} }
  \tl_set:Nx \l_mikew_groupfour_number_tl { #2 }
  \tl_replace_all:Nnn \l_mikew_groupfour_number_tl { ~ } { }
  \tl_reverse:N \l_mikew_groupfour_number_tl
  \regex_replace_all:nnN
   { [0-9]{4} } % search
   { \0 \c{l_mikew_groupfour_separator_tl} } % replace
   \l_mikew_groupfour_number_tl % token list
  \tl_reverse:N \l_mikew_groupfour_number_tl
  \regex_replace_once:nnN
   { \A \c{l_mikew_groupfour_separator_tl} }
   { }
   \l_mikew_groupfour_number_tl
  \tl_use:N  \l_mikew_groupfour_number_tl
 }

\ExplSyntaxOff

\begin{document}

\groupfour{ 123456789 }

\groupfour[\,]{1 2345 6789}

$\groupfour{12345678}$ % test for math mode

\end{document}

This reverses the input, after removing blank spaces; then after every group of four digits, the separator is inserted (in symbolic form); the string is reversed again and a leading separator is removed.

You can change the separator by calling \groupfour[<separator>]{<number>}.

enter image description here

An extended version for dealing also with decimal numbers. In the decimal part, groups of four digits are separated by thin spaces. It wouldn't be difficult to change it, according to needs.

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

\ExplSyntaxOn

\NewDocumentCommand{\groupfour}{O{,}m}
 {
  \mikew_groupfour:nn { #1 } { #2 }
 }

\tl_new:N \l_mikew_groupfour_separator_tl
\tl_new:N \l_mikew_groupfour_number_tl
\seq_new:N \l_mikew_groupfour_parts_seq

\cs_new_protected:Nn \mikew_groupfour:nn
 {
  \tl_set:Nn \l_mikew_groupfour_separator_tl { {#1} }
  \regex_split:nnN { \. } { #2 } \l_mikew_groupfour_parts_seq
  \tl_set:Nx 
   \l_mikew_groupfour_number_tl
   { \seq_item:Nn \l_mikew_groupfour_parts_seq { 1 } }
  \tl_replace_all:Nnn \l_mikew_groupfour_number_tl { ~ } { }
  \tl_reverse:N \l_mikew_groupfour_number_tl
  \__mikew_groupfour_replace:
  \tl_reverse:N \l_mikew_groupfour_number_tl
  \tl_use:N  \l_mikew_groupfour_number_tl
  \int_compare:nT { \seq_count:N \l_mikew_groupfour_parts_seq > 1 }
   {
    \tl_set:Nn \l_mikew_groupfour_separator_tl { {\,} }
    . % print the decimal point
    \tl_set:Nx 
     \l_mikew_groupfour_number_tl
     { \seq_item:Nn \l_mikew_groupfour_parts_seq { 2 } }
    \__mikew_groupfour_replace:
    \tl_use:N  \l_mikew_groupfour_number_tl
   }
 }

\cs_new_protected:Nn \__mikew_groupfour_replace:
 {
  \regex_replace_all:nnN
   { [0-9]{4} } % search
   { \0 \c{l_mikew_groupfour_separator_tl} } % replace
   \l_mikew_groupfour_number_tl % token list
  \regex_replace_once:nnN
   { \c{l_mikew_groupfour_separator_tl} \Z }
   { }
   \l_mikew_groupfour_number_tl
 }

\ExplSyntaxOff

\begin{document}

X\groupfour{ 123456789 }X

X\groupfour[\,]{1 2345 6789}X

X$\groupfour{12345678}$X

X\groupfour{1234567890.12345678}X

\end{document}

enter image description here

1
  • Thanks for the interesting answer. I have just tried it and it works!
    – MikeW
    Feb 11, 2018 at 14:31
5

For the sake of variety, here's a LuaLaTeX-based solution. It's very similar to to the one given in this answer. The solution defines a user macro called \groupfour, which invokes a Lua function that does the actual work. If the number (the argument of \groupfour) contains a decimal part, no commas are inserted in the decimal portion.

enter image description here

% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{siunitx}
\usepackage{luacode}
\begin{luacode}
function groupfour ( s )
    z = ""
    -- Check if number contains a decimal part. If so, don't
    -- insert commas in the decimal part.
    n = string.find ( s, "%." ) 
    if n then
       -- Set aside decimal part of number in string "z"
       z = string.sub ( s , n )
       s = string.sub ( s , 1 , n-1 )
    end 
    t = ""
    while string.len ( s ) > 4 do
        t = "{,}" .. string.sub ( s, -4 ) .. t
        s = string.sub ( s , 1, -5 ) 
    end
    tex.sprint ( s .. t .. z )
end
\end{luacode}
\newcommand\groupfour[1]{\directlua{groupfour(\luastring{#1})}}

\begin{document}
\num[group-separator={,}]{123456789}

\groupfour{123456789}
\end{document}

You must log in to answer this question.

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