- PR -

DecimalFormat について

投稿者投稿内容
ranco
大ベテラン
会議室デビュー日: 2007/11/02
投稿数: 112
投稿日時: 2007-12-01 18:31
""は数値の表現ではないので、一般の計算アプリケーション(科学、工学計算など)では使えません。事務アプリはあまり経験ありませんが、お金の計算なんかでは困りそう。

物理メディア上にどうプリントするかというレベルのモンダイと、数値の書式化というイシューは、別次元ではないでしょうか。
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2007-12-01 18:44
引用:

数値や日付は逆変換できないと実用性がかなり低くなってしまうと思います。


逆変換したいときは、逆変換できる書式を指定すればいいだけですよ。注意を払わないと元に戻せないというのは今でもあるわけだから。たとえば…

コード:
	//負数プリフィックスに数字を使うと元に戻せない。
	DecimalFormat f = new DecimalFormat("#;1#");
	
	long number = 123;
	
	System.out.println(number);
	System.out.println(f.parse(f.format(number)));
	
	//日付区切り文字なしで桁数可変だと元に戻せない。
	SimpleDateFormat f = new SimpleDateFormat("yMd");
	
	Date date = new Date(0);
	
	System.out.println(date);
	System.out.println(f.parse(f.format(date)));



引用:

DecimalFormatでは遭遇したことがありません。実装を思い返してみても結構使用していますので気になります。特定バージョンの問題でしょうか?


実装不具合ということではなく仕様がおかしいと思っているのですよ。

(1) 負数パターンとして数値部分の書式も指定できるのに、実は数値部分は無視されて正数パターンの数値部分書式が使われる。(まぎらわしい)

(2) 負数パターンのプリフィックスと正数パターンのプリフィックスが同じ場合、負数パターンのプリフィックスが無視されて、負数のときに標準のプリフィックスが付加される。(絶対値を表示したいときに困る、明示的に指定したものを無視するなんて余計なお世話)

引用:

パターンを値により変えるということをしてしまうと、利用者側の我々がおそらく混乱します。


私は上記のようなヘンテコ仕様のほうが混乱すると思いますけど。値 0 のときの、書式 # の振る舞いが変化するよりも、値 0 専用の書式を指定できるほうが直感的だと私は思っています。そのほうが柔軟性もありますし。(数量0のときはハイフンやらアスタリスクやら特別な記号を表示したいなんて案件もありますし。)

引用:

思うのですが、「0件」を特別扱いするか、ということに通じる問題のような気がします。Excel の #,### に限らず、自分で普通にフォーマッターを最低限コーディングすると数値の 0 は ""(長さ0の文字列)になるのが自然だと思います(もし "0" を出力する仕様にするならば、入力が 0 の時だけ特別に if で切り分けているはず)。また、小数も考えると、いっそう、そう思います。


内部の実装を想像してみると確かにそうですね。DecimalFormat は手抜きでこのような動作になっているのではなく、意図的にこういう動作をするように実装されているのでしょう。
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2007-12-02 09:20
引用:

暁さんの書き込み (2007-12-01 10:11) より:

これは同意しかねます。
そもそも負数パターンはプレフィックスのみが使用されますので、他のFormatとインターフェースが統一されていると考えます。
パターンを値により変えるということをしてしまうと、利用者側の我々がおそらく混乱します。


この手の業務アプリケーションを作成していると負数は括弧つきで扱うような事例にぶつかることがありますね。 Excel なんかでも用意されています。

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
大ベテラン
会議室デビュー日: 2006/06/28
投稿数: 116
投稿日時: 2007-12-02 11:55
論拠の導出過程がありませんでしたので、記述しておきます。

Java APIの仕様的には、""を数値や日付とは扱わないです。
これは、数値や日付のフォーマットで空文字列をパース出来ないことから判断しました。
ですから、空文字列を出力するように期待したフォーマットでも0が出力されるのだろうと考えました。

引用:

未記入さんの書き込み (2007-12-01 18:44) より:
逆変換したいときは、逆変換できる書式を指定すればいいだけですよ。注意を払わないと元に戻せないというのは今でもあるわけだから。たとえば…


これら例については、非実用的なパターンですので言及を控えさせていただきます。
引用:

引用:

DecimalFormatでは遭遇したことがありません。実装を思い返してみても結構使用していますので気になります。特定バージョンの問題でしょうか?


実装不具合ということではなく仕様がおかしいと思っているのですよ。

(1) 負数パターンとして数値部分の書式も指定できるのに、実は数値部分は無視されて正数パターンの数値部分書式が使われる。(まぎらわしい)

(2) 負数パターンのプリフィックスと正数パターンのプリフィックスが同じ場合、負数パターンのプリフィックスが無視されて、負数のときに標準のプリフィックスが付加される。(絶対値を表示したいときに困る、明示的に指定したものを無視するなんて余計なお世話)


私の投稿は、この点を確認しておきたいところから発したものでした。
未記入さんの投稿文面から判断して、負数フォーマットで出力したときに妙な値が出力されるものととれましたものですから。
不具合に遭遇されたのではないということで安心しました。

確かに仕様とは言え、負数フォーマットが指定できるのにフォーマットどおりに出力されないのは
分かりにくいといえるかもしれませんね。

私のDecimalFormatの仕様用途はせいぜいが、記録データの書き込み・読み込み程度です。
このとき使用するクラス内の処理では、双方向の変換を行うためのパターンは唯一のものであり、
可逆でなければならないし、正負のパターンが異なっていてもまずいので、
今回のように異なるパターンを使用するという頭が無かったのかもしれません。

(1)で指摘されている仕様は確かに、おかしいような気がしてきました。
ただ、(2)についてはぴんときません。
("絶対値: #; 絶対値: #"みたいな指定をするということかと考えてテストしてみましたが、-1をフォーマットすると"絶対値: 1"と表示されました。)

引用:

引用:

パターンを値により変えるということをしてしまうと、利用者側の我々がおそらく混乱します。


私は上記のようなヘンテコ仕様のほうが混乱すると思いますけど。値 0 のときの、書式 # の振る舞いが変化するよりも、値 0 専用の書式を指定できるほうが直感的だと私は思っています。そのほうが柔軟性もありますし。(数量0のときはハイフンやらアスタリスクやら特別な記号を表示したいなんて案件もありますし。)


負数パターンを指定できるのに、負数のフォーマットが反映されない点がおかしいのには賛同します。
ですが、"値 0 専用の書式"についてはやはり賛同できません。
冒頭で書きましたが、javaでは空文字列は数値になりません。
値0用のフォーマットを設定するのであれば、それに対しparseも行えないと一貫性がないです。
一貫性の無い動作は混乱を与えます。
(もちろんこれは私が考えているだけで誰に押し付けるつもりもないですし、SunのJava開発チームにしてみればそれこそ知ったこっちゃないでしょうが。)
特殊な書式が必要ならそれ用のフォーマッタを作成するだけです。

引用:

じゃんぬねっとさんの書き込み (2007-12-02 09:20) より:
引用:

暁さんの書き込み (2007-12-01 10:11) より:

これは同意しかねます。
そもそも負数パターンはプレフィックスのみが使用されますので、他のFormatとインターフェースが統一されていると考えます。
パターンを値により変えるということをしてしまうと、利用者側の我々がおそらく混乱します。


この手の業務アプリケーションを作成していると負数は括弧つきで扱うような事例にぶつかることがありますね。 Excel なんかでも用意されています。


Javaでも、Excel同様の機能を提供するためのAPIを持つPOIやe.spreadsheet等が対応していることは知っていますが、
自分が必要性を感じていなかったので、未記入さんの、0やnull用のフォーマットを持つべきという発言に反発してしまいました。
Cの出力書式では数値0は空白にはなりませんよね。scanfも空白を認識しない。
APIがどうあるかはその言語特有のものであって他言語がどうあるか、とは無関係であると考えます。
未記入さんとじゃんぬねっとさんの指摘で、負数フォーマットを指摘しているのに無視されるのはおかしくない?ってところには
自分の考えが足りなかった&なるほどと思っています。

ここの辺り対応するとなると、APIがどこまでやるか、互換性をどうするかという面を考えるとなかなか大変そうです。(SunのJava開発チームが)

[ メッセージ編集済み 編集者: 暁 編集日時 2007-12-02 12:00 ]

[ メッセージ編集済み 編集者: 暁 編集日時 2007-12-02 12:02 ]
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2007-12-02 17:51
引用:

負数は括弧つきで扱うような事例にぶつかることがありますね。


実際はサフィックスも指定できますので負数の括弧書きは問題ありません。Excel 同様に、#,##0;(#,##0) と指定できます。「プリフィックスのみ〜」という表現は、数値部分が指定できないことを意図していました。紛らわしくてすみません。

引用:

"絶対値: #; 絶対値: #"みたいな指定をするということかと考えてテストしてみましたが、-1をフォーマットすると"絶対値: 1"と表示されました。


そのテスト結果はおかしいですね。私の環境ではそのような結果にはなりません。実際には " 絶対値: 1" と先頭に半角スペースが付加されて出力されます。この先頭の半角スペースが邪魔だと思って書式指定を "絶対値: #;絶対値: #" と指定すると、(正数パターンと負数パターン同じになり負数パターンが無効化されるため) 出力が "-絶対値: 1" となってしまいます。つまり符号を無視して正数と負数で同じ出力をさせることができないのです。これも暁さんの言う可逆変換のためなのかな。(すでに反例を挙げてますが)そんな中途半端で厳密でない可逆変換など捨ててしまえと言いたい。

引用:

冒頭で書きましたが、javaでは空文字列は数値になりません。値0用のフォーマットを設定するのであれば、それに対しparseも行えないと一貫性がないです。


空文字列を parse できるようにしたらいいだけですよ。幸いなことに parse はクラスメソッドではなくインスタンスメソッドですから、書式が #,### で与えられた場合、値 0 を空文字として出力する、かつ、空文字が parse に入力されたら受理して 0 とすればいいだけ。0 専用パターン、null 専用パターンについても同じ。空文字に変換される値が唯ひとつである場合は、空文字を parse が受理すればよい。

引用:

APIがどうあるかはその言語特有のものであって他言語がどうあるか、とは無関係であると考えます。


まあ確かにそうですね。他の言語にこのような機能があるから Java でも同じ機能を実装しなければならない、ということはないでしょう。でも、他ではできるのに Java ではできなくて不便だねえ、と言われることはあるかもしれませんよ。少しは他の実装も気にしたほうがいいと思いますけど。

引用:

ここの辺り対応するとなると、APIがどこまでやるか、互換性をどうするかという面を考えるとなかなか大変そうです。


そうですね。今後、互換性が失われるような改善は期待できないと思っています。実際、使い勝手が悪い DecimalFormat なぞ使わずに、ずいぶん前に独自フォーマッタを自作
しましたので問題ありません。もともと独自フォーマッタを作成したのは、昔の Java では日付フォーマットで和暦が使えなかったからというのが理由ですけどね。VB6 と動作が違うと言われて、いつのまにか 0 専用パターン、null 専用パターンが追加されていきました。
大ベテラン
会議室デビュー日: 2006/06/28
投稿数: 116
投稿日時: 2007-12-02 19:17
引用:

未記入さんの書き込み (2007-12-02 17:51) より:
引用:

"絶対値: #; 絶対値: #"みたいな指定をするということかと考えてテストしてみましたが、-1をフォーマットすると"絶対値: 1"と表示されました。


そのテスト結果はおかしいですね。私の環境ではそのような結果にはなりません。実際には " 絶対値: 1" と先頭に半角スペースが付加されて出力されます。


フォーマットの前方スペースはカットされるものと思ってました。
フォーマットを修正して実行すると、確かに未記入さんのおっしゃる通り負数先頭に"-"が付加される結果になりました。
仕様の理解が足りず、お手数をおかけしました。
引用:

引用:

冒頭で書きましたが、javaでは空文字列は数値になりません。値0用のフォーマットを設定するのであれば、それに対しparseも行えないと一貫性がないです。


空文字列を parse できるようにしたらいいだけですよ。


javaは空文字列を数値として見なしてくれはしません。
私はこのことに拠って書き込みしているつもりです。
ですから、空文字列をparse出来るようにしたら良いという意見に賛同できないです。
引用:

引用:

APIがどうあるかはその言語特有のものであって他言語がどうあるか、とは無関係であると考えます。


まあ確かにそうですね。他の言語にこのような機能があるから Java でも同じ機能を実装しなければならない、ということはないでしょう。でも、他ではできるのに Java ではできなくて不便だねえ、と言われることはあるかもしれませんよ。少しは他の実装も気にしたほうがいいと思いますけど。


確かに他の言語にあって、自分の使用したい言語に無ければ不便に感じます。
ですが、言語ごとに目指すものが違いますからポリシーは違ってくるのが当然ではないでしょうか?
Javaの開発者は空文字を数値と見なさないほうがメリットが大きいと判断したのでしょうし、
我々は、未記入さんがそうしたように、それらをカスタマイズすることが出来ます。
スレ主に独自のフォーマッタを作成するよう勧めたのは、そういう意図であったと考えていたのですが。

実装については私がどうこう言ってもどうなるものでもありません。
JavaAPI開発者が不便に思えば変更されるのでしょう。

書き込みつづけられないかもしれませんので自分の発言についてまとめますが、
私が書き込みした理由はDecimalFormatが負数で妙な動作をするという書き込みのためであり、
スレ主に対する回答は、動作からの推測ではjavaでは""を数値とみなさないということです。

[ メッセージ編集済み 編集者: 暁 編集日時 2007-12-02 19:18 ]

[ メッセージ編集済み 編集者: 暁 編集日時 2007-12-02 19:19 ]
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2007-12-02 20:50
引用:

javaは空文字列を数値として見なしてくれはしません。


Java ってなんですか? Java の言語仕様として Format の振る舞いが規定されているわけではないですよね。java.text.Format のことを言っているのかなと思って調べてみても、空文字を parse できないとは書いてありません。もちろん、java.text.Format のサブクラスが空文字を parse できてはいけないとも書いてありません。

さらに、あたなの言う可逆変換についても、java.text.Format の説明では format した出力文字列が parse で元に戻せる保証はないとの注意書きがなされていますよ。

空文字列を数値として見なしてくれないのは、java.text.Format および既知のサブクラスがそうなっているというだけの話。Java が空文字列を数値として見なしてくれない、という表現は誤り。DecimalFormat について言えば、0 専用パターンを追加して、format による空文字列出力を可能とし、また parse による空文字列受理を可能にしても誰も困らないし、完全な下位互換性を維持することが可能です。
大ベテラン
会議室デビュー日: 2006/06/28
投稿数: 116
投稿日時: 2007-12-03 23:45
引用:

未記入さんの書き込み (2007-12-02 20:50) より:
引用:

javaは空文字列を数値として見なしてくれはしません。


Java ってなんですか? Java の言語仕様として Format の振る舞いが規定されているわけではないですよね。java.text.Format のことを言っているのかなと思って調べてみても、空文字を parse できないとは書いてありません。もちろん、java.text.Format のサブクラスが空文字を parse できてはいけないとも書いてありません。


Formatの振る舞いが規定されていないというのは、確かにそうなのかもしれません。
Javaの言語仕様に精通しているなどとうぬぼれるつもりもありません。
ですが、Javaの言語仕様として空文字列を数値としては扱わない、
厳密には数値は必ず1桁以上を持つと定義されていることは知っています。
これが空文字列をparse出来ないと発言した理由です。

実際、new Integer("")やInteger.parseInt("")などが失敗しますので
ここに矛盾は無いですね。

引用:

さらに、あたなの言う可逆変換についても、java.text.Format の説明では format した出力文字列が parse で元に戻せる保証はないとの注意書きがなされていますよ。


そうかもしれません。
自分の経験という狭い範囲で、そうであるはずだと思い込んで大きな口をきいてしまいました。
そうなってくると、最初の発言は的を外していますね。
数値用フォーマッタでの出力だから、""にはなりえないということになりますか。

[ メッセージ編集済み 編集者: 暁 編集日時 2007-12-03 23:55 ]

[ メッセージ編集済み 編集者: 暁 編集日時 2007-12-03 23:56 ]

[ メッセージ編集済み 編集者: 暁 編集日時 2007-12-04 01:41 ]

スキルアップ/キャリアアップ(JOB@IT)