DecimalFormat 分组符号的不同表示
Posted
技术标签:
【中文标题】DecimalFormat 分组符号的不同表示【英文标题】:Different representations of DecimalFormat grouping symbol 【发布时间】:2020-06-05 07:09:44 【问题描述】:今天我在下一个代码清单中发现了一个语言环境问题。我的目标是用瑞士德语语言环境(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 我发现我可以访问和修改 DecimalFormat 以实现我的目标。虽然单元测试对这个结果很满意,但我并不满意。从DecimalFormat API 我不明白为什么分组符号偏离了预期的千位分隔符。因为它是同一个字符,所以我看到的唯一罪魁祸首是 IDE(或者更确切地说是它使用的字体)。
System.out.println(Integer.valueOf('’'));
39
System.out.println(Integer.valueOf('\''));
8217
我的问题是:如何编写单元测试,使其不易受到同一字符的不同表示的影响?
【问题讨论】:
你为什么要写JUnit测试来测试JDK的代码? 【参考方案1】:总结
对于瑞士德语语言环境,使用’
(不是'
)作为千位分隔符的Java 输出在我看来是正确的。 ICU文档和Java也参考’
。
鉴于此,您的单元测试不必关注千位分隔符的不同表示形式 - 除非您明确要使用 '
,而不是 ’
。
背景
两个不同的字符是:
'
- 标准键盘撇号(Unicode U+0027)
’
- 右单引号(Unicode U+2019)
根据问题中链接到的语言环境页面 (the de-CH locale page here),数字分组分隔符是 '
- 标准撇号。
但是,我认为此文档可能不正确 - 或者,至少是误导 - 在您的问题的上下文中。
Java Locale
对象从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
语言标签是创建“瑞士德语”标签的另一种方法 - 这是问题中引用的页面所引用的标签。
但 ICU “gsw” 语言环境也有 this other page。在this 页面上,分组分隔符是’
右单引号。仅通过查看页面很难判断 - 但如果您复制/粘贴到等宽字体,您会看到差异。
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
的语言环境称为“瑞士德语”。
基于de-CH
的语言环境称为“德语(瑞士)”。细微的差别。
无论如何,最终结果是数字使用’
分隔符,而不是标准撇号。
如本答案开头所述,您可能希望/需要使用 '
作为分隔符,作为对“官方”语言环境格式的有意识更改。如果是这样,那么您可以使用您提到的十进制格式对象。
【讨论】:
以上是关于DecimalFormat 分组符号的不同表示的主要内容,如果未能解决你的问题,请参考以下文章