# 自定义格式

> 原文： [https://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html](https://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html)

您可以使用`DecimalFormat`类将十进制数格式化为特定于语言环境的字符串。此类允许您控制前导和尾随零，前缀和后缀，分组（千）分隔符和小数分隔符的显示。如果要更改格式符号（例如小数点分隔符），可以将`DecimalFormatSymbols`与`DecimalFormat`类一起使用。这些类在数字格式化方面提供了极大的灵活性，但它们可以使您的代码更加复杂。

下面的文本使用演示`DecimalFormat`和`DecimalFormatSymbols`类的示例。此材料中的代码示例来自名为 [`DecimalFormatDemo`](examples/DecimalFormatDemo.java) 的示例程序。

## 构建模式

使用模式`String`指定`DecimalFormat`的格式属性。该模式确定格式化数字的外观。有关模式语法的完整说明，请参见[数字格式模式语法](#numberpattern)。

下面的示例通过将模式`String`传递给`DecimalFormat`构造函数来创建格式化程序。 `format`方法接受`double`值作为参数，并在`String`中返回格式化的数字：

```
DecimalFormat myFormatter = new DecimalFormat(pattern);
String output = myFormatter.format(value);
System.out.println(value + " " + pattern + " " + output);

```

前面的代码行的输出如下表所述。 `value`是要格式化的数字，`double`。 `pattern`是指定格式属性的`String`。 `output`是`String`，表示格式化的数字。

<caption>Output from `DecimalFormatDemo` Program</caption>
| `value` | `pattern` | `output` | 说明 |
| --- | --- | --- | --- |
| 123456.789 | ###，###。### | 123,456.789 | 井号（＃）表示一个数字，逗号是分组分隔符的占位符，句点是小数分隔符的占位符。 |
| 123456.789 | ###。## | 123456.79 | `value`在小数点右边有三位数字，但`pattern`只有两位数。 `format`方法通过四舍五入来处理这个问题。 |
| 123.78 | 000000.000 | 000123.780 | `pattern`指定前导零和尾随零，因为使用 0 字符而不是井号（＃）。 |
| 12345.67 | $ ###，###。### | $ 12,345.67 | `pattern`中的第一个字符是美元符号（$）。请注意，它紧接在格式化的`output`中最左边的数字之前。 |
| 12345.67 | \ u00A5 ###，###。### | ¥12,345.67 | `pattern`指定日元（¥）的货币符号，Unicode 值为 00A5。 |

## 区域敏感格式

前面的示例为默认`Locale`创建了`DecimalFormat`对象。如果想要`DecimalFormat`对象作为非默认`Locale`，则实例化`NumberFormat`然后将其转换为`DecimalFormat`。这是一个例子：

```
NumberFormat nf = NumberFormat.getNumberInstance(loc);
DecimalFormat df = (DecimalFormat)nf;
df.applyPattern(pattern);
String output = df.format(value);
System.out.println(pattern + " " + output + " " + loc.toString());

```

运行上一个代码示例将导致后面的输出。格式化的数字位于第二列，随`Locale`而变化：

```
###,###.###      123,456.789     en_US
###,###.###      123.456,789     de_DE
###,###.###      123 456,789     fr_FR

```

到目前为止，这里讨论的格式模式遵循美国英语的惯例。例如，在模式###，###。##中，逗号是千位分隔符，句点表示小数点。如果最终用户没有接触到它，那么这个约定很好。但是，某些应用程序（如电子表格和报表生成器）允许最终用户定义自己的格式设置模式。对于这些应用程序，最终用户指定的格式模式应使用本地化表示法。在这些情况下，您需要在`DecimalFormat`对象上调用`applyLocalizedPattern`方法。

## 改变格式符号

您可以使用 [DecimalFormatSymbols](https://docs.oracle.com/javase/8/docs/api/java/text/DecimalFormatSymbols.html) 类更改`format`方法生成的格式化数字中出现的符号。这些符号包括小数分隔符，分组分隔符，减号和百分号等。

下一个示例通过对数字应用奇怪的格式来演示`DecimalFormatSymbols`类。不寻常的格式是调用`setDecimalSeparator`，`setGroupingSeparator`和`setGroupingSize`方法的结果。

```
DecimalFormatSymbols unusualSymbols = new DecimalFormatSymbols(currentLocale);
unusualSymbols.setDecimalSeparator('|');
unusualSymbols.setGroupingSeparator('^');

String strange = "#,##0.###";
DecimalFormat weirdFormatter = new DecimalFormat(strange, unusualSymbols);
weirdFormatter.setGroupingSize(4);

String bizarre = weirdFormatter.format(12345.678);
System.out.println(bizarre);

```

运行时，此示例以奇怪的格式打印数字：

```
1^2345|678

```

## 数字格式模式语法

您可以按照以下 BNF 图表指定的规则为数字设计自己的格式模式：

```
pattern    := subpattern{;subpattern}
subpattern := {prefix}integer{.fraction}{suffix}
prefix     := '\\u0000'..'\\uFFFD' - specialCharacters
suffix     := '\\u0000'..'\\uFFFD' - specialCharacters
integer    := '#'* '0'* '0'
fraction   := '0'* '#'*

```

上图中使用的符号如下表所示：

| 符号 | 描述 |
| --- | --- |
| `X*` | 0 个或更多个 X 实例 |
| `(X &#124; Y)` | X 或 Y |
| `X..Y` | 从 X 到 Y 的任何字符，包括在内 |
| `S - T` | S 中的字符，除了 T 中的字符 |
| `{X}` | X 是可选的 |

在前面的 BNF 图中，第一个子模式指定了正数的格式。第二个子模式是可选的，指定负数的格式。

虽然未在 BNF 图中注明，但逗号可能出现在整数部分内。

在子模式中，您可以使用特殊符号指定格式。这些符号如下表所述：

| 符号 | 描述 |
| --- | --- |
| 0 | 一个数字 |
| ＃ | 一个数字，零显示为缺席 |
| 。 | 小数分隔符的占位符 |
| ， | 占位符用于分组分隔符 |
| Ë | 为指数格式分隔尾数和指数 |
| ; | 分隔格式 |
| - | 默认负前缀 |
| ％ | 乘以 100 并显示为百分比 |
| ？ | 乘以 1000 并按照 mille 显示 |
| ¤ | 货币符号;用货币符号代替;如果翻倍，用国际货币符号代替;如果存在于模式中，则使用货币小数分隔符而不是小数分隔符 |
| X | 任何其他字符都可以在前缀或后缀中使用 |
| “ | 用于引用前缀或后缀中的特殊字符 |