DecimalFormat 分组符号的不同表示

Different representations of DecimalFormat grouping symbol

今天我在下一个代码清单中发现了一个语言环境问题。我的目标是使用瑞士德语语言环境 (de-CH) 格式化数字,以便千位以撇号 (') 分隔,小数点以句点 (.) 分隔。根据 ICU,这是该国家/地区的默认设置。

final NumberFormat format = NumberFormat.getNumberInstance(new Locale("en", "US"));
format.setMinimumFractionDigits(1);
format.setMaximumFractionDigits(1);

assertEquals("1'000.2", format.format(1000.2455));

这在我使用瑞士德语语言环境的同事机器上按预期工作。但是,当我 运行 在我的机器上使用美国语言环境时,测试失败,因为组分隔符是 ' 而不是 ' (apostrophes).

expected:<1[']000.2> but was:<1[’]000.2>
Expected :1'000.2
Actual   :1’000.2

通过另一个SO post I found that I can access and modify the DecimalFormat to achieve my goal. While the unit test is satisfied with this result, I am not. From the DecimalFormat API我不明白为什么分组符号偏离预期的千位分隔符。因为它是同一个字符,所以我看到的唯一罪魁祸首是 IDE (或者更确切地说是它使用的字体)。

System.out.println(Integer.valueOf('’'));
39
System.out.println(Integer.valueOf('\''));
8217

我的问题是:如何编写单元测试才能使其不易受到同一字符的不同表示形式的影响?

总结

使用 (不是 ')作为千位分隔符的 Java 输出在我看来是正确的,适用于瑞士德语语言环境。 ICU 文档和 Java 也参考了

鉴于此,您的单元测试不必关注千位分隔符的不同表示形式 - 除非您明确想要使用 ',而不是

背景

两个不同的角色是:

  • ' - 标准键盘撇号 (Unicode U+0027)
  • - 右单引号 (Unicode U+2019)

根据问题 (the de-CH locale page here) 中链接的语言环境页面,数字分组分隔符是 ' - 标准撇号。

但是,我认为此文档在您的问题上下文中可能不正确 - 或者至少具有误导性。

Java Locale object takes its language subtag values from the IANA Language Subtag Registry.

瑞士德语的注册表项是这样的:

Type: language
Subtag: gsw
Description: Swiss German
Description: Alemannic
Description: Alsatian
Added: 2006-03-08
Suppress-Script: Latn

因此,我们使用 "gsw" 为瑞士德语构建 Java 语言环境,如下所示:

Locale swissGermanLocale = new Locale("gsw");

de-CH 语言标签是另一种创建 "Swiss German" 标签的方法 - 这是问题中引用的页面所引用的标签。

但是 ICU "gsw" 语言环境也有 this other page。在这个页面,分组分隔符是右单引号。很难说,只是看页面 - 但如果你 copy/paste 等宽字体,你会看到区别。

Java 代码示例

看着Java,我们可以这样写:

double d = 12345.67;
// This line is just so my console prints out the correct UTF-8 characters:
PrintStream out = new PrintStream(System.out, true, StandardCharsets.UTF_8);

Locale swissGermanLocale = new Locale("gsw");
//Locale swissGermanLocale = new Locale("de", "CH");
out.println(swissGermanLocale.getDisplayName());  // Swiss German

final NumberFormat gswFormat = NumberFormat.getNumberInstance(swissGermanLocale);

// Find out what the grouping separator is for the given locale:
DecimalFormat decimalFormat = (DecimalFormat)
NumberFormat.getNumberInstance(swissGermanLocale);
char c = decimalFormat.getDecimalFormatSymbols().getGroupingSeparator();
out.println(c);  // ’

out.println(gswFormat.format(d));  // 12’345.67

请注意,基于 gsw 的语言环境称为 "Swiss German"。

基于 de-CH 的语言环境称为 "German (Switzerland)"。细微差别。

无论如何,最终结果是数字使用 分隔符,而不是标准的撇号。

如本回答开头所述,您可以 want/need 使用 ' 作为分隔符,这是对 "official" 语言环境格式的有意识改变。如果是这样,那么您可以使用您提到的十进制格式对象。