DecimalFormatの実用ガイド

DecimalFormatの実用ガイド

1. 概要

この記事では、DecimalFormatクラスとその実際の使用法について説明します。

これはNumberFormatのサブクラスであり、事前定義されたパターンを使用して10進数のString表現をフォーマットできます。

逆に使用して、文字列を数値に解析することもできます。

2. 仕組み

数値をフォーマットするには、パターンを定義する必要があります。パターンは、テキストと混合される可能性のある一連の特殊文字です。

11個の特殊パターン文字がありますが、最も重要なものは次のとおりです。

  • 0-指定された場合は数字を出力し、それ以外の場合は0を出力します

  • #-指定されている場合は数字を出力し、それ以外の場合は何も出力しない

  • 。 -小数点区切り文字を配置する場所を示します

  • 、–はグループ化区切りを配置する場所を示します

パターンが数値に適用されると、そのフォーマット規則が実行され、特定のLocaleが指定されていない限り、結果はJVMのLocaleDecimalFormatSymbolに従って出力されます。

次の例の出力は、英語のLocaleで実行されているJVMからのものです。

3. 基本的なフォーマット

次のパターンで同じ数値をフォーマットすると、どの出力が生成されるかを見てみましょう。

3.1. 単純な小数

double d = 1234567.89;
assertThat(
  new DecimalFormat("#.##").format(d)).isEqualTo("1234567.89");
assertThat(
  new DecimalFormat("0.00").format(d)).isEqualTo("1234567.89");

ご覧のとおり、パターンが数字よりも小さい場合でも、整数部分は決して破棄されません。

assertThat(new DecimalFormat("#########.###").format(d))
  .isEqualTo("1234567.89");
assertThat(new DecimalFormat("000000000.000").format(d))
  .isEqualTo("001234567.890");

代わりにパターンが数値よりも大きい場合、整数部分と小数部分の両方でゼロが追加され、ハッシュは削除されます。

3.2. 丸め

パターンの小数部分に入力数値の精度全体を含めることができない場合は、丸められます。

ここでは、.89の部分が.90に丸められ、その後0が削除されています。

assertThat(new DecimalFormat("#.#").format(d))
  .isEqualTo("1234567.9");

ここでは、0.89の部分が1.00に丸められ、次に.00が削除され、1が7に合計されます。

assertThat(new DecimalFormat("#").format(d))
  .isEqualTo("1234568");

デフォルトの丸めモードはHALF_EVEN,ですが、setRoundingModeメソッドを使用してカスタマイズできます。

3.3. グルーピング

グループ化区切りは、自動的に繰り返されるサブパターンを指定するために使用されます。

assertThat(new DecimalFormat("#,###.#").format(d))
  .isEqualTo("1,234,567.9");
assertThat(new DecimalFormat("#,###").format(d))
  .isEqualTo("1,234,568");

3.4. 複数のグループ化パターン

一部の国では、番号付けシステムにさまざまな数のグループ化パターンがあります。

インドの記数法は、,,。##の形式を使用します。この形式では、最初のグループ化区切り文字のみが3つの数値を保持し、他のすべては2つの数値を保持します。

これは、DecimalFormatクラスを使用して実現することはできません。このクラスは、検出された最新のパターンのみを左から右に保持し、以前のグループ化パターンを無視して整数に適用します。

パターン,,,,を使用しようとすると、,に再グループ化され、,,, ##に再配布されます。

複数のグループ化パターンマッチングを実現するには、独自のString操作コードを作成するか、それを可能にするIcu4J’s DecimalFormatを試す必要があります。

3.5. 文字列リテラルの混合

パターン内でStringリテラルを混在させることができます。

assertThat(new DecimalFormat("The # number")
  .format(d))
  .isEqualTo("The 1234568 number");

エスケープすることで、Stringリテラルとして特殊文字を使用することもできます。

assertThat(new DecimalFormat("The '#' # number")
  .format(d))
  .isEqualTo("The # 1234568 number");

4. ローカライズされたフォーマット

多くのcountriesは英語の記号を使用せず、小数点記号としてコンマを使用し、グループ区切り文字としてドットを使用します。

たとえば、イタリア語のLocaleを使用してJVMで,.パターンを実行すると、1.234.567,89が出力されます。

これは場合によってはi18nの便利な機能ですが、特定のJVMに依存しない形式を適用したい場合もあります。

これを行う方法は次のとおりです。

assertThat(new DecimalFormat("#,###.##",
  new DecimalFormatSymbols(Locale.ENGLISH)).format(d))
  .isEqualTo("1,234,567.89");
assertThat(new DecimalFormat("#,###.##",
  new DecimalFormatSymbols(Locale.ITALIAN)).format(d))
  .isEqualTo("1.234.567,89");

関心のあるLocaleが、DecimalFormatSymbolsコンストラクターでカバーされているものに含まれていない場合は、getInstanceメソッドで指定できます。

Locale customLocale = new Locale("it", "IT");
assertThat(new DecimalFormat(
  "#,###.##",
   DecimalFormatSymbols.getInstance(customLocale)).format(d))
  .isEqualTo("1.234.567,89");

5. 科学的記数法

Scientific Notationは、仮数と10の指数の積を表します。 番号1234567.89は、12.3456789 * 10 ^ 5(ドットは5桁シフトされます)として表すこともできます。

5.1. E-表記

10の指数を表すEパターン文字を使用して、科学的記数法で数値を表すことができます。

assertThat(new DecimalFormat("00.#######E0").format(d))
  .isEqualTo("12.3456789E5");
assertThat(new DecimalFormat("000.000000E0").format(d))
  .isEqualTo("123.456789E4");

指数の後の文字数が関係していることに注意する必要があるため、10 ^ 12を表現する必要がある場合は、E0ではなくE00が必要です。

5.2. 工学的記数法

工学的記数法と呼ばれる特定の形式の科学的記数法を使用するのが一般的です。これは、たとえばキロ(10 ^ 3)、メガ(10 ^ 6)、ギガ(10 ^ 6)などの測定単位を使用する場合に、3の倍数として表現されるように結果を調整します。 10 ^ 9)など。

この種の表記を適用するには、整数の最大桁数(#で表され、小数点の左側にある文字)を調整して、最小数(0で表される文字)よりも大きくなるようにします。 1.1。

これにより、指数は最大数の倍数になります。したがって、このユースケースでは、最大数を3にする必要があります。

assertThat(new DecimalFormat("##0.######E0")
  .format(d)).isEqualTo("1.23456789E6");
assertThat(new DecimalFormat("###.000000E0")
  .format(d)).isEqualTo("1.23456789E6");

6. 構文解析

parseメソッドを使用してStringNumberに解析する方法を見てみましょう。

assertThat(new DecimalFormat("", new DecimalFormatSymbols(Locale.ENGLISH))
  .parse("1234567.89"))
  .isEqualTo(1234567.89);
assertThat(new DecimalFormat("", new DecimalFormatSymbols(Locale.ITALIAN))
  .parse("1.234.567,89"))
  .isEqualTo(1234567.89);

戻り値は小数点の存在によって推測されないため、返されたNumberオブジェクトの.doubleValue().longValue()などのメソッドを使用して、出力に特定のプリミティブを適用できます。

次のようにBigDecimalを取得することもできます。

NumberFormat nf = new DecimalFormat(
  "",
  new DecimalFormatSymbols(Locale.ENGLISH));
((DecimalFormat) nf).setParseBigDecimal(true);

assertThat(nf.parse("1234567.89"))
  .isEqualTo(BigDecimal.valueOf(1234567.89));

7. スレッドセーフ

DecimalFormat isn’t thread-safeであるため、スレッド間で同じインスタンスを共有する場合は特に注意が必要です。

8. 結論

DecimalFormatクラスの主な使用法と、その長所と短所.を見てきました。

いつものように、完全なソースコードはover on Githubで利用できます。