En python
re.sub(r"(?<=.)(?=(?:...)+$)", ",", stroke )
Pour diviser un nombre par triplets, par exemple:
echo 123456789 | python -c 'import sys;import re; print re.sub(r"(?<=.)(?=(?:...)+$)", ",", sys.stdin.read());'
123,456,789
Comment faire de même avec bash/awk?
Avec sed
:
$ echo "123456789" | sed 's/\([[:digit:]]\{3\}\)\([[:digit:]]\{3\}\)\([[:digit:]]\{3\}\)/\1,\2,\3/g'
123,456,789
(Notez que cela ne fonctionne que pour exactement 9 chiffres!)
ou ceci avec sed
:
$ echo "123456789" | sed ':a;s/\B[0-9]\{3\}\>/,&/;ta'
123,456,789
Avec printf
:
$ LC_NUMERIC=en_US printf "%'.f\n" 123456789
123,456,789
bash
de printf
prend en charge à peu près tout ce que vous pouvez faire dans la fonction C printf
type printf # => printf is a Shell builtin
printf "%'d" 123456 # => 123,456
printf
de coreutils fera de même
/usr/bin/printf "%'d" 1234567 # => 1,234,567
Vous pouvez utiliser numfmt:
$ numfmt --grouping 123456789
123,456,789
Ou:
$ numfmt --g 123456789
123,456,789
Notez que numfmt n'est pas un utilitaire POSIX, il fait partie de GNU coreutils.
cat <<'EOF' |
13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096
EOF
Perl -wpe '1 while s/(\d+)(\d\d\d)/$1,$2/;'
produit:
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
Ceci est accompli en divisant la chaîne de chiffres en 2 groupes, le groupe de droite avec 3 chiffres, le groupe de gauche avec tout ce qui reste, mais au moins un chiffre. Ensuite, tout est remplacé par les 2 groupes, séparés par une virgule. Cela continue jusqu'à ce que la substitution échoue. Les options "wpe" sont pour lister les erreurs, enfermer l'instruction dans une boucle avec une impression automatique et prendre l'argument suivant comme "programme" Perl (voir la commande perldoc perlrun pour plus de détails).
Meilleurs voeux ... cheers, drl
Avec quelques implémentations awk
:
echo "123456789" | awk '{ printf("%'"'"'d\n",$1); }'
123,456,789
"%'"'"'d\n"
est: "%
(guillemet simple) (guillemet double) (guillemet simple) (guillemet double) (guillemet simple) d\n"
Cela utilisera le séparateur de milliers configuré pour vos paramètres régionaux (généralement ,
en anglais, espace en français, .
en espagnol/allemand ...). Identique à celui retourné par locale thousands_sep
awk
et bash
ont de bonnes solutions intégrées, basées sur printf
, comme décrit dans les autres réponses. Mais d'abord, sed
.
Pour sed
, nous devons le faire "manuellement". La règle générale est que si vous avez quatre chiffres consécutifs, suivis d'un non-chiffre (ou fin de ligne), une virgule doit être insérée entre le premier et le deuxième chiffre.
Par exemple,
echo 12345678 | sed -re 's/([0-9])([0-9]{3})($|[^0-9])/\1,\2\3/'
imprimera
12345,678
Nous devons évidemment continuer à répéter le processus, afin de continuer à ajouter suffisamment de virgules.
sed -re ' :restart ; s/([0-9])([0-9]{3})($|[^0-9])/\1,\2\3/ ; t restart '
Dans sed
, la commande t
spécifie une étiquette vers laquelle passer si le dernier s///
la commande a réussi. Je définis donc une étiquette avec :restart
, pour qu'il recule.
Voici une démo bash (sur ideone ) qui fonctionne avec n'importe quel nombre de chiffres:
function thousands {
sed -re ' :restart ; s/([0-9])([0-9]{3})($|[^0-9])/\1,\2\3/ ; t restart '
}
echo 12 | thousands
echo 1234 | thousands
echo 123456 | thousands
echo 1234567 | thousands
echo 123456789 | thousands
echo 1234567890 | thousands
Un cas d'utilisation courant consiste à modifier la sortie d'un pipeline de commandes afin que les nombres décimaux soient imprimés avec mille séparateurs. Plutôt que d'écrire une fonction ou un script, je préfère utiliser une technique que je peux personnaliser à la volée pour toute sortie d'un pipeline Unix.
J'ai trouvé que printf
(fourni par Awk) était le moyen le plus flexible et le plus mémorable pour y parvenir. Le caractère apostrophe/guillemet simple est spécifié par [~ # ~] posix [~ # ~] as a modifier to format decimal et a l'avantage d'être sensible aux paramètres régionaux, de sorte qu'il n'est pas limité à l'utilisation de virgules.
Lors de l'exécution de commandes Awk à partir d'un shell Unix, il peut être difficile de saisir un caractère guillemet simple dans une chaîne délimitée par des guillemets simples (pour éviter l'expansion du shell des variables de position, par exemple, $1
). Dans ce cas, je trouve que le moyen le plus lisible et le plus fiable pour saisir le caractère guillemet simple est de le saisir comme une séquence d'échappement octale (commençant par \0
).
Exemple:
printf "first 1000\nsecond 10000000\n" |
awk '{printf "%9s: %11\047d\n", $1, $2}'
first: 1,000
second: 10,000,000
Sortie simulée d'un pipeline montrant quels répertoires utilisent le plus d'espace disque:
printf "7654321 /home/export\n110384 /home/incoming\n" |
awk '{printf "%22s: %9\047d\n", $2, $1}'
/home/export: 7,654,321
/home/incoming: 110,384
D'autres solutions sont répertoriées dans Comment échapper à un guillemet simple dans awk .
Remarque: comme mis en garde dans Print a Single Quote , il est recommandé d'éviter l'utilisation de séquences d'échappement hexadécimales car elles ne fonctionnent pas de manière fiable sur différents systèmes.
Une solution bash
/awk
(comme demandé) qui fonctionne quelle que soit la longueur du numéro et utilise ,
Quel que soit le paramètre thousands_sep
Des paramètres régionaux, et où que vous soyez les chiffres sont en entrée et évite d'ajouter le séparateur de milliers après dans 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}'
Donne:
not number 123,456,789,012,345,678,901,234,567,890 1,234.56789
Avec des implémentations de awk
comme mawk
qui ne prennent pas en charge les opérateurs d'expression régulière d'intervalle, changez l'expression rationnelle en /(^|[^.0123456789])[0123456789][0123456789][0123456789][0123456789]+/
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
$ echo 1232323 | awk '{printf(fmt,$1)}' fmt="%'6.3f\n"
12,32,323.000
Si vous regardez de gros chiffres, je n'ai pas pu faire fonctionner les solutions ci-dessus. Par exemple, permet d'obtenir un très grand nombre:
$ echo 2^512 |bc -l|tr -d -c [0-9] 13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096
Remarque J'ai besoin de tr
pour supprimer la sortie de nouvelle ligne antislash de bc. Ce nombre est trop grand pour être traité comme un nombre flottant ou un bit fixe dans awk, et je ne veux même pas construire une expression rationnelle suffisamment grande pour prendre en compte tous les chiffres de sed. Je peux plutôt l'inverser et mettre des virgules entre des groupes de trois chiffres, puis l'annuler:
echo 2^512 |bc -l|tr -d -c [0-9] |rev |sed -e 's/\([0-9][0-9][0-9]\)/\1,/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
Je voulais aussi avoir la partie après le séparateur décimal correctement séparé/espacé, j'ai donc écrit ce script sed qui utilise certaines variables Shell pour s'adapter aux préférences régionales et personnelles. Il prend également en compte différents conventions pour le nombre de chiffres regroupés :
#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"'%\1__HIDETHOUSSEP__%g
:restartA ; s%\([0-9]\)\([0-9]\{'"$GROUPBEFDS"'\}\)\(['"$DECIMALSEP$THOUSSEP"']\)%\1'"$THOUSSEP"'\2\3% ; t restartA
:restartB ; s%\('"$DECIMALSEP"'\([0-9]\{'"$GROUPAFTDS"'\}\'"$THOUSSEP"'\)*\)\([0-9]\{'"$GROUPAFTDS"'\}\)\([0-9]\)%\1\3'"$THOUSSEP"'\4% ; t restartB
:restartC ; s%\([^'"$DECIMALSEP"'][0-9]\+\)\([0-9]\{'"$GROUPBEFDS"'\}\)\($\|[^0-9]\)%\1'"$THOUSSEP"'\2\3% ; t restartC
s%__HIDETHOUSSEP__%\'"$THOUSSEP"'%g'
}