【问题标题】:Is the String Constructor from UTF-8 Broken?UTF-8 的字符串构造函数是否损坏?
【发布时间】:2015-05-21 23:10:37
【问题描述】:

我有以下代码从缓冲区加载空终止的多字节字符串。它名义上将数据解释为 UTF-8,但如果转换失败,它会将数据解释为 ISO-8859-1。代码如下:

@Override
   public String format(String date_format, boolean use_locale, int precision)
   {
      String rtn = null;
      int len = 0;
      for(int i = 0; i < max_len; ++i)
      {
         if(storage[storage_offset + i] != 0)
            ++len;
         else
            break;
      }
      try
      {
         rtn = new String(storage, storage_offset, len, "UTF-8");
      }
      catch(UnsupportedEncodingException e1)
      {
         try
         {
            rtn = new String(storage, storage_offset, len, "ISO-8859-1");
         }
         catch(UnsupportedEncodingException e2)
         { }
      }
      return rtn;
   }

我的意图是,如果 UTF-8 的字符串解码失败,我们可以回退。这取决于抛出的 UnsupportedEncodingException。我已经对此代码进行了测试,该代码通过了扩展字符(大于 128 的代码)而没有预期的 UTF-8 模式。我发现没有抛出异常,并且为转换后的字符串显示了未知的字形。我的问题是标准库实现是否有任何更改会导致异常不被抛出?

【问题讨论】:

  • 请提供 MCVE。

标签: java android utf-8


【解决方案1】:

UnsupportedEncodingException 如果字符集本身不受支持(也就是说,您指定了一个字符集而系统无法识别该名称),则抛出 UnsupportedEncodingException - 如果字节编码不正确,则不会。请注意,采用java.nio.charset.Charset 的相应构造函数确实 抛出该异常(因为没有名称可以映射到Charset,因此不可能不存在映射)。

String(byte[], int, int, String) 的文档指定了行为(即未指定:))并提出修复建议:

当给定字节在给定字符集中无效时,此构造函数的行为未指定。当需要对解码过程进行更多控制时,应使用CharsetDecoder 类。

【讨论】:

    【解决方案2】:

    根据that String constructor 的文档,仅当指定的 charsetName 未知时才会引发 UnsupportedEncodingException。

    当给定字节在给定字符集中无效时,此构造函数的行为未指定。当需要对解码过程进行更多控制时,应使用 CharsetDecoder 类。

    【讨论】:

      【解决方案3】:

      您可以测试字符集是否可用。
      要获取可用的字符集,请使用:

      SortedMap<String, Charset> availableCharsets = Charset.availableCharsets();
          for (Map.Entry<String, Charset> entrySet : availableCharsets.entrySet()) {
              String key = entrySet.getKey();
              Charset value = entrySet.getValue();
              System.out.println("key: " + key + " value: " + value.name());
          }
          System.out.println("The default Charset is: " + Charset.defaultCharset().name());
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-05-22
        • 2015-06-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-20
        • 1970-01-01
        相关资源
        最近更新 更多