【问题标题】:java.net.URI non-standard encoding for Unicode character errorUnicode 字符错误的 java.net.URI 非标准编码
【发布时间】:2020-06-11 11:15:54
【问题描述】:

以下代码行:

    URI url = new URI("http://host?xyz=abc%u021B");

给出错误:

java.net.URISyntaxException:索引 19 处的转义对格式错误: http://host?xyz=abc%u021B

原因是%u021B的存在,一个non-standard encoding for Unicode character

有没有标准的方法来处理这个问题?

【问题讨论】:

  • 这不是 URI,java.net.URI 不能直接使用它。你追求什么结果?
  • @Joe 为什么你认为它不是 URI?
  • 按照定义,我不认为你可以有一个非标准问题的标准解决方案。
  • 也许“不是 URI”过于宽泛,但它不是 RFC 3986 sense 中的 URI。要么将其转换为一个,要么在不使用标准库的情况下对其进行处理。

标签: java unicode urlencode


【解决方案1】:

有没有标准的方法来处理这个问题?

RFC 3986 之后,这不是一个有效的 URI,正确的行为是拒绝它。

WHATWG living standard 提出了一种更稳健的按字面处理字符的行为:

否则,如果字节为 0x25 (%) 并且输入中字节之后的下两个字节不在 0x30 (0) 到 0x39 (9)、0x41 (A) 到 0x46 (F) 和 0x61 (a ) 到 0x66 (f),全包,追加字节到输出。

由于这不适用,请按原样添加%,这意味着:

%u021B

被视为:

%25u021B

%uxxxx 编码方案在draft-duerst-iri 中指定。如果你想实现它,伪代码是:

  1. 匹配%u([a-f0-9]{4})
  2. 将十六进制数字解析为字节数组b
  3. 拍下new String(b, UTF_16BE).getBytes(UTF_8)
  4. 追加each byte in that result as %xx
  5. 替换原来的%uxxxx匹配

【讨论】:

    【解决方案2】:

    你可以转换 "%u021B" -> "\\u021B"
    然后使用 apache.commons.lang3.StringEscapeUtils 将其转换为 unicode

    示例:

    String str = "http://host?xyz=abc%u021B";
    
    str = str.replaceAll("%u", "\\\\u");
    str = StringEscapeUtils.unescapeJava(str);
    
    URI uri = new URI(str);
    System.out.println("It works!");
    System.out.println(str.toString());
    

    【讨论】:

    • 这是一个好的开始。唯一的问题: %u021B 需要替换为标准编码的字符串。现在它看起来是由StringEscapeUtils.unescapeJava解码的
    【解决方案3】:

    根据@Roy 的回答,此代码有效:

    public static URI toUri(String uri) throws URISyntaxException {
        StringBuilder stringBuilder = new StringBuilder(uri);
        int index = stringBuilder.indexOf("%u");
        while (index > -1) {
            try {
                String substring = stringBuilder.substring(index, index + 6).replaceAll("%u", "\\\\u");
                String encoded = URLEncoder.encode(StringEscapeUtils.unescapeJava(substring), StandardCharsets.UTF_8);
                stringBuilder.replace(index, index + 6, encoded);
                index = stringBuilder.indexOf("%u", index + 6);
            } catch (Exception e) {
                throw new URISyntaxException(uri, e.getMessage());
            }
        }
        return new URI(stringBuilder.toString());
    }
    

    这个想法是用 unicode 字符 \uxxxx 的编码值替换每个组 %uxxxx

    这样http://host?xyz=abc%u021B 变成http://host?xyz=abc%C8%9B,最后一个是标准URI。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-06-19
    • 1970-01-01
    • 2013-10-29
    • 2011-08-11
    • 1970-01-01
    • 2013-10-17
    • 2015-02-03
    • 1970-01-01
    相关资源
    最近更新 更多