UWSCで数字の3桁区切りをする

UWSC公式掲示板に面白いお題があったので参戦してみた。
「数値に3桁カンマ区切りを付与する」
その感想。

みなさんの答え

まずは、しろまささんがシンプルに文字列操作。
次に、LinersさんがFORMAT関数で桁を揃えCOPYで区切り" ,"を""置換でTRIMというトリック。
再び、しろまささんが正規表現で"^(-?\d+)(\d{3})"を"$1,$2"に置換繰り返し。
そして、独覚さんのexcel.WorksheetFunction.Text(値,"#,##0")
ここで、私がオライリー本から投入。"(\d)(?=(\d{3})+(?!\d))"を"$1,"に全て置換。
さらに、stuncloudさんがPowershellのフォーマットコマンド。
最後?に、森さんのVBScript FormatNumber関数。




やー、皆さん、さすがですね!

それぞれに個人的な感想(えらそうですみません)

しろまささんの文字列操作

シンプルで良いです。
見た目も判り易い。
剰余演算の便利さを知らない人は、よく読むと良いです。
ただし、小数には未対応。
IF文はいらないかなー。なくてもできるけど、あった方がシンプルですね。

Linersさんのトリック

相変わらず素晴らしい。
何でそれで上手くいくの!!!理不尽!、、、とか初見では言いたくなる。
実用性を考えると、最大桁数固定で充分なことは多いので、速度的にお勧め。
Excel使わないなら、一番実用的に思う。
ただし、小数には未対応。

しろまささんの正規表現

これまたシンプルで良いです。
小数に対応しているのが素晴らしい。小数そのまま保持。
何をしているのか判り易い正規表現というのが良いです。

独覚さんのExcel使用

私もまずこれを思いついたのですが、先を越されました。
Excelオブジェクトを持っているなら、これがお勧め。
小数は四捨五入。

オライリー正規表現

"(\d)(?=(\d{3})+(?!\d))"を"$1,"に全て置換。
意味不明です。
正規表現内でループを処理させて先読みしまくり。
先読み濫用のため遅いと思うけど、ま、影響でるほど長い文字列操作しないでしょう、と。
javascriptだと一行で終わり。

"-1234567".replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,")


念のため解説。というか「-1234567」を正規表現エンジンになったつもりで処理。

  • 先頭の「-」は(\d)にマッチしない
  • 次「1」は(\d)にマッチ。続く先読みを処理すると「234」「567」でOK。「1」を「1,」に置換。結果「-1,234567」
  • 次「2」は(\d)にマッチ。続く先読みを処理すると「345」だけど残り「67」で3つないからマッチしない
  • 次「3」は(\d)にマッチ。略。残り3つないからマッチしない
  • 次「4」は(\d)にマッチ。続く先読みを処理すると「567」でOK。「4」を「4,」に置換。結果「-1,234,567」
  • 次「5」は(\d)にマッチ。続く先読みを処理すると残り「67」で3つないからマッチしない
  • 以下略。最後までいって終了

一体どれだけ先読みすれば気が済むっちゅうねん。「7」は何回読まれるのだろう?


小数が3桁を超えるとぎゃー。
そう、小数4桁以上には未対応。


肯定後読みの方法も、ほぼ同じ思想です。
Powershell使いの方ならこんな感じ。
.NETは後読みできる!

[Text.RegularExpressions.Regex]::Replace("-1234567", "(?<=\d)(?=(\d{3})+$)", ",")

これは思いつくのに、何故か、肯定後読みの排除に気づかない、、、。
数字には触らない、区切りのゼロ幅にカンマを入れる、と思い込みすぎですね。
あと、肯定先読み内で否定先読みできるなんて、本を見るまで考えもしなかった。
$と(?!\d)はほぼ同じ働きです。置換可能。
$パターンの場合、小数は非対応。相手にしません。

stuncloudさんのPowershellフォーマットコマンド

Powershell、便利だけどUWSCからは遅すぎなんですよねー。
Get-Memberコマンドにはお世話になってますので、もうちょっと早ければ使いたいところ。
(何?IEオブジェクトのプロパティ・メソッド等を知りたい?
 New-Object -ComObject InternetExplorer.Application | Get-Member | Out-GridView
 タブ補完も素敵。上の入力は
 new-o<#TAB> -c<#TAB> InternetExplorer.Application | get-m<#TAB> | out-g<#TAB>
 Powershellも出来ないことはないですね!)
XPもWindows Updateで入れるべき。
小数は四捨五入です。

森さんのFormatNumber

そういえば、FormatNumberなんて関数がありましたね。
柔軟性が高いです。
小数点以下を自分でコントロールできるのが素晴らしい。
Excel方式もPowershell方式もできるけど、「桁数」指定じゃない)
ただ、いちいち関数を作ると遅いと思うので

DIM scpt = CreateOleObj("ScriptControl")
scpt.language = "VBScript"
scpt.AddCode("Function re(num, digit): re=FormatNumber(num, digit): End Function")
Msgbox(scpt.Run("re", 123456789, 0))
Msgbox(scpt.Run("re", 1234.56789, 2))

で良いかも。
小数点以下の桁数指定が省略不可になりますが、、、。
小数は指定桁数で四捨五入。


なお、3桁区切りが「,」で小数点が「.」なのは、国によるので注意。
Wikipediaの小数点の項目でも参照してください。
FormatNumberは対応しているのだろうか?
英語圏や中国あたりのアジア勢が同じなので、ほぼ問題ないですが、、、。

まとめ

Excelオブジェクトを使ってよいなら

独覚さんの、excel.WorksheetFunction.Text(値, "#,##0")
これ以外ありえないと思うけど、、、他の選択肢は次くらいかな?

小数点以下桁数を柔軟に制御したいなら

森さんの、FormatNumber
小数を扱うなら、これにしとくのが一番。
でも、次も参考になるかも。

小数には興味ないけどそのまま保持、正規表現の勉強したい

しろまささんの正規表現で"^(-?\d+)(\d{3})"を"$1,$2"置換繰り返し。
正規表現というとマニアがすぐおどろおどろしいのを書きたがりますが、シンプルなのは重要。

実用性を求めるなら

LinersさんのFORMAT/COPY/REPLACE/TRIM
実はこれで充分なことが余りに多い。
なんでも柔軟にしようとするのはオーバースペックだと気づくがいい!
COMも使わず、速さは一番、、、だと思う。

プログラム初心者で勉強したいなら

しろまささんのシンプル文字操作。
基本はとても大事。
COMオーバーヘッドによっては、実は柔軟かつ早いのがこれ。

あとは一部のマニア向け

stuncloudさん、すみません。
でもそれはPoershellマニアがやること。
だって、、、遅いし、、、環境選ぶし。
オライリー本のは、正規表現マニア向け。
なんかすごいことしてる気になるのがメリット。