关于Java:Android上的toUpperCase对于双参数和默认的希腊语和土耳其语语言环境是不正确的

toUpperCase on Android is incorrect for two-argument and default Greek and Turkish Locales

我在使用touppercase()和默认区域设置时遇到希腊语和土耳其语的问题,更有趣的是,这两个参数的区域设置构造函数。

问题发生在Galaxy选项卡s2 Android 5.0.2上(也在5.1.1上复制)此问题可通过设置应用程序和更多区域设置2重现。

考虑到这个标题的价值:_?兰姆?ε-ε-ε-δ-π?α?

这些电话很管用。

1
2
title.toUpperCase(new Locale("el_GR"))
title.toUpperCase(new Locale("el-GR"))

两者都会产生正确的结果。如果你仔细看,T和P后面有记号。

?∑∑△_?γ

但是,对于默认的区域设置和两个参数的区域设置构造函数,我得到了不同的结果。

这是我的平板电脑上的默认区域设置:

1
Locale.getDefault() ==  el_GR

在一般的touppercase()中使用

1
2
3
public String toUpperCase() {
    return CaseMapper.toUpperCase(Locale.getDefault(), this, value, offset, count);
}

当我调用这个函数时,它返回错误的结果。

1
title.toUpperCase()

注意T和P上缺少的勾号。

_∧∑_∑

如果将两个参数构造函数用于新的区域设置,则得到相同的结果:

1
title.toUpperCase(new Locale("el","GR"))

_∧∑_∑

将这些行添加到应用程序启动中可以解决问题,但这非常简单。

1
2
3
String language = Locale.getDefault().getLanguage();
String country = Locale.getDefault().getCountry();
Locale.setDefault(new Locale(language +"-" + country));

我宁愿简单地遵从默认的区域设置。


正如您在casemapper.java中看到的,方法toUpperCase对于阿塞拜疆、立陶宛、土耳其和希腊地区具有特殊的行为:

1
2
3
4
5
6
7
8
9
10
11
public static String toUpperCase(Locale locale, String s, int count) {
    String languageCode = locale.getLanguage();
    if (languageCode.equals("tr") || languageCode.equals("az") || languageCode.equals("lt")) {
        return ICU.toUpperCase(s, locale);
    }
    if (languageCode.equals("el")) {
        return EL_UPPER.get().transliterate(s);
    }

    ...
}

为什么根据所使用的Locale的类型,会得到不同的结果?

让我们尝试分析创建的不同类型的Locale

1
2
3
4
5
6
7
8
locale = new Locale("el_GR");
Log.d(TAG, String.format("[el_GR] Language: '%s' ~ Country: '%s'", locale.getLanguage(), locale.getCountry()));

locale = new Locale("el","GR");
Log.d(TAG, String.format("[el, GR] Language: '%s' ~ Country: '%s'", locale.getLanguage(), locale.getCountry()));

locale = Locale.getDefault(); //Device with el_GR language
Log.d(TAG, String.format("[default] Language: '%s' ~ Country: '%s'", locale.getLanguage(), locale.getCountry()));

结果如下:

1
2
3
[el_GR] Language: 'el_gr' ~ Country: ''
[el, GR] Language: 'el' ~ Country: 'GR'
[default] Language: 'el' ~ Country: 'GR'

正如您在手工创建的只有一个参数的Locale中所看到的,语言是el_gr,而对于其他两种情况,语言是el。只有当语言代码为trazltel时,toUpperCase才有不同的行为,否则行为正常。因此,输出是不同的。

不幸的是,如果您想要勾号,唯一可行的解决方案是只使用一个参数的Locale构造函数。