You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JDK升级11后阿拉伯RTL场景NumberFormat负数解析异常问题

问题复现代码
Locale locale = new Locale("ar", "AE");
NumberFormat format = NumberFormat.getNumberInstance(locale);                
System.out.println(format.parse("55-"));

上述代码在JDK 8环境下执行返回-55,在JDK 11环境下执行返回55;同环境下调用format.parse("-55")方法会抛出ParseException。

版本行为差异的根本原因

核心差异来自JDK版本迭代中区域设置(Locale)数据源的默认规则切换:

  • JDK 8及更早版本默认使用JRE自带的兼容型区域数据(COMPAT),这套数据对ar_AE(阿拉伯联合酋长国阿拉伯语)的数字解析规则做了非标准的宽松适配:既支持前缀ASCII减号识别负数,也错误兼容了后缀ASCII减号的写法,会把"55-"解析为-55,不符合Unicode针对阿拉伯语RTL(从右到左)场景的官方本地化规范。
  • 从JDK 9开始,CLDR(Unicode通用区域数据仓库)被设为最高优先级的区域数据来源,JDK 11绑定的是高版本CLDR规则,严格遵循ar_AE区域的数字格式标准:
    • 阿拉伯语RTL场景下的标准负号不是ASCII编码的连字符-(U+002D)
    • 默认解析模式下,遇到数字串尾部的非合法数字字符会直接截断,返回已解析完成的数字部分,因此"55-"只会解析出前面的55,尾部的ASCII减号被直接忽略
    • 如果把ASCII减号放在数字开头,因为起始字符不属于当前Locale下的合法数字起始字符,解析会直接中断抛出ParseException
Java 11中正确解析阿拉伯语RTL场景负数的方案

根据业务兼容需求,可以选择以下三种方案:

  • 方案1:遵循CLDR标准格式解析
    ar_AE区域CLDR规范规定的标准负数,使用Unicode数学减号−(U+2212,注意和ASCII连字符区分)作为负号,逻辑字符串格式为−55,RTL渲染时负号会自动显示在数字的视觉左侧,直接用默认配置的NumberFormat解析该格式字符串即可得到正确的-55结果。
  • 方案2:开启宽松解析兼容旧写法
    如果业务需要兼容"55-"、"-55"这类ASCII减号的旧写法,手动调用NumberFormat的setLenient(true)方法开启宽松解析即可,示例代码:
    Locale locale = new Locale("ar", "AE");
    NumberFormat format = NumberFormat.getNumberInstance(locale);
    // 开启宽松解析模式
    format.setLenient(true);
    System.out.println(format.parse("55-")); // 输出-55
    System.out.println(format.parse("-55")); // 输出-55
    
  • 方案3:全局切换回JDK8兼容数据源
    如果需要全局复用JDK8的解析行为,不需要修改业务代码,直接在JVM启动参数中添加如下配置,将JDK自带的兼容型区域数据优先级调到CLDR之前即可:
    -Djava.locale.providers=COMPAT,CLDR
    

内容的提问来源于stack exchange,提问作者igce

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 02:24:34