Adicionar separador de milhares em um número

30

Em python

 re.sub(r"(?<=.)(?=(?:...)+$)", ",", stroke ) 

Para dividir um número por trios, por exemplo:

 echo 123456789 | python -c 'import sys;import re; print re.sub(r"(?<=.)(?=(?:...)+$)", ",",  sys.stdin.read());'
 123,456,789

Como fazer o mesmo com o bash / awk?

    
por user2496 06.02.2014 / 07:48

12 respostas

23

com sed :

$ echo "123456789" | sed 's/\([[:digit:]]\{3\}\)\([[:digit:]]\{3\}\)\([[:digit:]]\{3\}\)/,,/g'
123,456,789

(Observe que isso só funciona com exatamente 9 dígitos!)

ou isso com sed :

$ echo "123456789" | sed ':a;s/\B[0-9]\{3\}\>/,&/;ta'
123,456,789

com printf :

$ LC_NUMERIC=en_US printf "%'.f\n" 123456789
123,456,789
    
por 06.02.2014 / 08:20
42

bash printf suporta praticamente tudo que você pode fazer na função printf C

type printf           # => printf is a shell builtin
printf "%'d" 123456   # => 123,456

printf do coreutils fará o mesmo

/usr/bin/printf "%'d" 1234567   # => 1,234,567
    
por 06.02.2014 / 23:40
4
cat <<'EOF' |
13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096
EOF
perl -wpe '1 while s/(\d+)(\d\d\d)/$1,$2/;'

produz:

13,407,807,929,942,597,099,574,024,998,205,846,127,479,365,820,592,393,377,723,561,443,721,764,030,073,546,976,801,874,298,166,903,427,690,031,858,186,486,050,853,753,882,811,946,569,946,433,649,006,084,096

Isto é conseguido dividindo a cadeia de dígitos em 2 grupos, o grupo da direita com 3 dígitos, o grupo da esquerda com o que quer que restar, mas pelo menos um dígito. Então tudo é substituído pelos dois grupos, separados por uma vírgula. Isso continua até que a substituição falhe. As opções "wpe" são para listagem de erros, coloque a instrução dentro de um loop com uma impressão automática e tome o próximo argumento como o "programa" perl (veja o comando perldoc perlrun para detalhes).

Felicidades ... felicidades, drl

    
por 16.10.2017 / 22:16
3

Você pode usar o numfmt:

$ numfmt --grouping 123456789
123,456,789

Ou:

$ numfmt --g 123456789
123,456,789

Note que numfmt não é um utilitário POSIX, é parte do GNU coreutils.

    
por 21.01.2018 / 17:10
2

awk e bash têm boas soluções incorporadas, com base em printf , conforme descrito nas outras respostas. Mas primeiro, sed .

Para sed , precisamos fazer "manualmente". A regra geral é que, se você tiver quatro dígitos consecutivos, seguidos por um não dígito (ou fim de linha), uma vírgula deve ser inserida entre o primeiro e o segundo dígitos.

Por exemplo,

echo 12345678 | sed -re 's/([0-9])([0-9]{3})($|[^0-9])/,/'

imprimirá

12345,678

Obviamente, precisamos continuar repetindo o processo para continuar adicionando vírgulas suficientes.

sed -re ' :restart ; s/([0-9])([0-9]{3})($|[^0-9])/,/ ; t restart '

Em sed , o comando t especifica um rótulo para o qual o últimos/// comando foi bem-sucedido. Portanto, defino um rótulo com :restart , para que ele salte de volta.

Aqui está uma demonstração do bash (em ideone ) que funciona com qualquer número de dígitos:

function thousands {
    sed -re ' :restart ; s/([0-9])([0-9]{3})($|[^0-9])/,/ ; t restart '
}                                                 
echo 12 | thousands
echo 1234 | thousands
echo 123456 | thousands
echo 1234567 | thousands
echo 123456789 | thousands
echo 1234567890 | thousands
    
por 09.07.2015 / 19:47
2

Com algumas implementações de awk :

echo "123456789" | awk '{ printf("%'"'"'d\n",$1); }'  

123,456,789  

"%'"'"'d\n" is: "% (aspas simples) (aspas duplas) (aspas simples) (aspas duplas) (aspas simples) d \ n "

Isso usará o separador de milhar configurado para sua localidade (geralmente , em inglês, espaço em francês, . em espanhol / alemão ...). O mesmo que retornado por locale thousands_sep

    
por 16.10.2016 / 19:02
1
$ echo 1232323 | awk '{printf(fmt,$1)}' fmt="%'6.3f\n"
12,32,323.000
    
por 09.01.2017 / 19:15
1

Se você estiver procurando por números GRANDES, não consegui fazer as soluções acima funcionarem. Por exemplo, vamos obter um número realmente grande:

$ echo 2^512 |bc -l|tr -d -c [0-9] 13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096

Note que preciso do tr para remover a saída de nova linha da barra invertida de bc. Esse número é muito grande para ser tratado como um float ou um número fixo de bits no awk, e eu nem quero criar um regexp grande o suficiente para considerar todos os dígitos do sed. Em vez disso, posso invertê-lo e colocar vírgulas entre grupos de três dígitos e depois invertê-lo:

echo 2^512 |bc -l|tr -d -c [0-9] |rev |sed -e 's/\([0-9][0-9][0-9]\)/,/g' |rev 13,407,807,929,942,597,099,574,024,998,205,846,127,479,365,820,592,393,377,723,561,443,721,764,030,073,546,976,801,874,298,166,903,427,690,031,858,186,486,050,853,753,882,811,946,569,946,433,649,006,084,096

    
por 14.10.2017 / 07:39
1
a="13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096"

echo "$a" | rev | sed "s#[[:digit:]]\{3\}#&,#g" | rev

13,407,807,929,942,597,099,574,024,998,205,846,127,479,365,820,592,393,377,723,561,443,721,764,030,073,546,976,801,874,298,166,903,427,690,031,858,186,486,050,853,753,882,811,946,569,946,433,649,006,084,096
    
por 03.06.2018 / 08:53
1

Um caso de uso comum para mim é modificar a saída de um pipeline de comando para que números decimais sejam impressos com mil separadores. Em vez de escrever uma função ou script, prefiro usar uma técnica que eu possa personalizar rapidamente para qualquer saída de um pipeline Unix.

Eu achei o printf (fornecido pela Awk) como a forma mais flexível e memorável de conseguir isso. O apóstrofo / caractere de aspas simples é especificado por POSIX como um modifier para formatar números decimais e tem a vantagem de estar ciente do código de idioma, para que não fique restrito ao uso de caracteres vírgula. / p>

Ao executar comandos Awk a partir de um shell Unix, pode haver dificuldades em inserir um caractere de aspas simples dentro de uma string delimitada por aspas simples (para evitar a expansão do shell de variáveis posicionais, por exemplo, $1 ). Nesse caso, acho que a maneira mais legível e confiável de inserir o caractere de aspas simples é inseri-lo como uma sequência de escape octal (começando com %code% ).

Exemplo:

printf "first 1000\nsecond 10000000\n" |
  awk '{printf "%9s: %117d\n", $1, $2}'
  first:       1,000
 second:  10,000,000

Saída simulada de um pipeline mostrando quais diretórios estão usando mais espaço em disco:

printf "7654321 /home/export\n110384 /home/incoming\n" |
  awk '{printf "%22s: %97d\n", $2, $1}'
  /home/export: 7,654,321
/home/incoming:   110,384

Outras soluções estão listadas em Como escapar de uma aspa simples dentro do awk .

Observação: como foi advertido em Imprimir um orçamento simples , recomenda-se evitar o uso de seqüências de escape hexadecimais, pois elas não trabalhar de forma confiável em diferentes sistemas.

    
por 11.01.2019 / 20:03
0

Eu também queria ter a parte após o separador decimal corretamente separado / espaçado, portanto, eu escrevi este script sed que usa algumas variáveis de shell para se ajustar às preferências regionais e pessoais. Ele também leva em consideração diferentes convenções para o número de dígitos agrupados :

#DECIMALSEP='.' # usa                                                                                                               
DECIMALSEP=','  # europe

#THOUSSEP=',' # usa
#THOUSSEP='.' # europe
#THOUSSEP='_' # underscore
#THOUSSEP=' ' # space
THOUSSEP=' '  # thinspace

# group before decimal separator
#GROUPBEFDS=4   # china
GROUPBEFDS=3    # europe and usa

# group after decimal separator
#GROUPAFTDS=5   # used by many publications 
GROUPAFTDS=3


function digitgrouping {
  sed -e '
    s%\([0-9'"$DECIMALSEP"']\+\)'"$THOUSSEP"'%__HIDETHOUSSEP__%g
    :restartA ; s%\([0-9]\)\([0-9]\{'"$GROUPBEFDS"'\}\)\(['"$DECIMALSEP$THOUSSEP"']\)%'"$THOUSSEP"'% ; t restartA
    :restartB ; s%\('"$DECIMALSEP"'\([0-9]\{'"$GROUPAFTDS"'\}\'"$THOUSSEP"'\)*\)\([0-9]\{'"$GROUPAFTDS"'\}\)\([0-9]\)%'"$THOUSSEP"'% ; t restartB
    :restartC ; s%\([^'"$DECIMALSEP"'][0-9]\+\)\([0-9]\{'"$GROUPBEFDS"'\}\)\($\|[^0-9]\)%'"$THOUSSEP"'% ; t restartC
    s%__HIDETHOUSSEP__%\'"$THOUSSEP"'%g'
}
    
por 27.05.2018 / 09:56
0

Uma solução bash / awk (conforme solicitado) que funciona independentemente do tamanho do número e usa , , independentemente da configuração thousands_sep da localidade, e onde quer que os números estejam na entrada e evite adicionar o separador de milhar depois em 1.12345 :

echo not number 123456789012345678901234567890 1234.56789 |
  awk '{while (match($0, /(^|[^.0123456789])[0123456789]{4,}/))
        $0 = substr($0, 1, RSTART+RLENGTH-4) "," substr($0, RSTART+RLENGTH-3)
        print}'

Dá:

not number 123,456,789,012,345,678,901,234,567,890 1,234.56789

Com awk implementações como mawk que não suportam os operadores regex de intervalo, altere o regexp para /(^|[^.0123456789])[0123456789][0123456789][0123456789][0123456789]+/

    
por 03.04.2019 / 15:59