桁区切り記号を数字で追加します


36

Pythonで

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

番号をトリプレットで分割するには、たとえば:

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

bash / awkで同じことをする方法は?

回答:


29

sed

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

(これは正確に9桁でのみ機能することに注意してください!)

またはこれでsed

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

printf

$ LC_NUMERIC=en_US printf "%'.f\n" 123456789
123,456,789

私はまた、awkのにしようとしているが、それは最後にカンマを追加しますecho 123456789 | awk '$0=gensub(/(...)/,"\\1,","g")'
ラーフルパティル

今私は得るが、それは複雑なようだecho 123456789 | awk '$0=gensub(/(...)/,"\\1,","g"){sub(",$",""); print}'
ラフルパティル14

1
最初にsed機能するのは、数字が正確に9桁の場合のみです。のprintfはzshでは機能しません。したがって、2番目sed答えがおそらく最良です。
パトリック14

1
@RahulPatilこれは、桁数が3の倍数である場合にのみ正常に機能します。「12345678」で試してみて、意味がわかります。
パトリック14

1
できるecho 123456789 | awk '{printf ("%'\''d\n", $0)}'(明らかにLinuxで常に動作するとは限らない!?が、AIXとSolarisでは正常に動作する)
Johan 14年

51

bashprintfサポートあなたが行うことができますほとんどすべてprintfのC関数を

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

printf coreutilsからも同じことが行われます

/usr/bin/printf "%'d" 1234567   # => 1,234,567

これは現在もサポートzshされていますこちらの投稿を更新しまし
don_crissti

1
私はbash 4.1.2を使用していますが、サポートしていません... :(
msb

@msbシステムのに依存しているようvsnprintfです。GNU / Linuxシステムでは、glibcが、少なくとも1995年以来、それを支えてきたように見える
ミケル

2
注意printfは、現在のロケールにコンマ、ドット、または何もないかもしれない千桁区切りを使用しますexport LC_NUMERIC="en_US"カンマを強制する場合にできます。
-medmunds

サポートされているロケールのリストを取得しますlocale -a。私は使用しなければなりen_US.utf8
ませんでした-eludom

7

numfmtを使用できます。

$ numfmt --grouping 123456789
123,456,789

または:

$ numfmt --g 123456789
123,456,789

numfmtはPOSIXユーティリティではなく、GNU coreutilsの一部であることに注意してください。


1
「グループ化」のヒントをありがとう。2番目の例(--g)では-d, --grouping、二重ハイフネーションには長いオプションが必要なため、次のように記述しますか?
ホッピングバニー

--g代わりに、私のために罰金を働き--grouping、すなわちnumfmt --g 1234567890numfmt --grouping 1234567890同じことを行います。その非常に便利な小さなユーティリティ。
マットスト

4
cat <<'EOF' |
13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096
EOF
perl -wpe '1 while s/(\d+)(\d\d\d)/$1,$2/;'

生成するもの:

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

これは、数字の文字列を2つのグループに分割することで達成されます。右側のグループは3桁、左側のグループは残りのものがありますが、少なくとも1桁です。次に、すべてがコンマで区切られた2つのグループに置き換えられます。これは、置換が失敗するまで続きます。オプション「wpe」はエラーのリスト用で、ステートメントを自動印刷でループ内に囲み、次の引数をperl「プログラム」として取ります(詳細については、perldoc perlrunコマンドを参照してください)。

最高の願い...乾杯、DRL


匿名のフィードバックに感謝します。ダウン票でさえも有用ですが、説明されている場合にのみ、それが間違っていると思われたことについてコメントしてください。おかげで...歓声
DRL

ここでのダウン投票は、コマンドが何をするのかを説明しなかったからだと思います。OPは以前に使用したことがないかもしれないのでBASH/ AWK代替を要求しましたPERL。いずれにせよ、コマンドが何をするのかを説明するのが最善です-特にワンライナーの場合。
AnthonyK

@AnthonyK-おそらく説明をありがとう。コメントを追加して、その仕組みを簡単に説明しました。私は代替案が有用であることが多いと思いますが、おそらく使用perlが指摘されて持っていない...歓声に関するあなたのポイント
DRL

このページでsedとpythonの提案を試しました。perlスクリプトは、ファイル全体で機能する唯一のスクリプトでした。ファイルはテキストと数字でファイルされました。
マーク

3

いくつかのawk実装では:

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

123,456,789  

"%'"'"'d\n"is:("%シングルクォート)(ダブルクォート)(シングルクォート)(ダブルクォート)(シングルクォート)d \ n"

それはあなたのロケールに設定された千の区切り文字を使用します(通常,は英語のロケールで、フランス語でスペース.、スペイン語/ドイツ語で...)。によって返されるものと同じlocale thousands_sep


2

私の一般的な使用例は、コマンドパイプラインの出力を変更して、10進数が千の区切り文字で印刷されるようにすることです。むしろ機能やスクリプトを書くよりも、私は私がその場でカスタマイズできるという技術を使用することを好む任意の Unixのパイプラインからの出力を。

私はprintf、これを達成するための最も柔軟で記憶に残る方法である(Awk提供)ことを発見しました。アポストロフィ/シングルクォート文字は、10進数をフォーマットするための修飾子としてPOSIXによって指定され、カンマ文字の使用に制限されないため、ロケールを認識するという利点があります。

UnixシェルからAwkコマンドを実行する場合、単一引用符で区切られた文字列内に単一引用符を入力するのが難しい場合があります(たとえば、位置変数のシェル拡張を避けるため$1)。この場合、シングルクォート文字を入力する最も読みやすく信頼性の高い方法は、8進エスケープシーケンスとして入力することです(先頭は\0)。

例:

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

どのディレクトリが最もディスク容量を使用しているかを示すパイプラインのシミュレーション出力:

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

他のソリューションは、awk内の単一引用符をエスケープする方法にリストされています。

注:「一重引用符の印刷」で警告されているように、16進のエスケープシーケンスは異なるシステム間で確実に機能しないため、使用を避けることをお勧めします。


1
ここにリストされているすべてのawkベースの回答の中で、これは間違いなく最も優雅です(IMHO)。他のソリューションのように、引用を他の引用とハックする必要はありません。
TSJNachos117

ありがとう@ TSJNachos117最も難しいのは、アポストロフィ文字の8進数エンコーディングがであることを思い出すことです\047
アンソニーG-モニカの正義

2

awkそしてbash良いが内蔵されているソリューションに基づいてprintf、他の回答で説明したように。しかし、最初にsed

のためにsed、「手動で」それを行う必要があります。一般的な規則は、4桁の連続した数字の後に非数字(または行末)が続く場合、最初の数字と2番目の数字の間にコンマを挿入することです。

例えば、

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

印刷します

12345,678

十分なコンマを追加し続けるために、明らかにプロセスを繰り返し続ける必要があります。

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

sed、コマンドはt、最後のs///コマンドが成功した場合にジャンプするラベルを指定します。したがって、:restartジャンプして戻るために、でラベルを定義します。

任意の桁数で機能するbashデモ(ideone)を次に示します。

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


1

大きな数字を見ていると、上記のソリューションを機能させることができませんでした。たとえば、非常に大きな数を取得できます。

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

注:trbcからバックスラッシュ改行出力を削除する必要があります。この数はawkで浮動小数点数または固定ビット数として扱うには大きすぎるため、sedのすべての桁を考慮に入れるのに十分な大きさの正規表現を作成したくはありません。むしろ、私はそれを逆にして、3桁のグループの間にコンマを入れてから、逆にすることができます:

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


2
いい答えだ。ただし、Awkで大きな数値を使用するときに問題が発生したことはありません。多くのRed HatおよびDebianベースのディストリビューションであなたの例を試しましたが、すべての場合において、Awkはその数が多くても問題はありませんでした。私はそれについてもう少し考えましたが、私が試したすべてのシステムは64ビットでした(私はサポートされていないRHEL 5を実行している非常に古いVMでさえ)と思いました。32ビットOSを実行している古いラップトップをテストするまで、問題を再現できませんでしたawk: run time error: improper conversion(number 1) in printf("%'d
アンソニーG-モニカの正義

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

番号の桁数が3の倍数である場合には、偽の主要コンマを追加
ステファンChazelas

@StéphaneChazelas:最後のrevコマンドの出力を取得して、それをにパイプすることができsed 's/^,//g'ます。
TSJNachos117

0

また、小数点区切り文字のの部分正しく分離/スペースしたかったので、いくつかのシェル変数を使用して地域や個人の好みに合わせて調整するこのsedスクリプトを書きました。また、一緒にグループ化される桁数のさまざまな規則も考慮します。

#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'
}

0

A bash/ awk番号および使用の長さに関係なく動作する(要求されたように)溶液,ロケールのに関係なくthousands_sep設定、数字を入力しているとどこで後千枚のセパレータを追加することを回避します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}'

与える:

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

そのawkような実装でmawkは区間正規表現演算子をサポートしていないため、正規表現を/(^|[^.0123456789])[0123456789][0123456789][0123456789][0123456789]+/

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.