【问题标题】:ISO-8858-1 to UTF-8 only in URL, only invalid charactersISO-8858-1 到 UTF-8 仅在 URL 中,只有无效字符
【发布时间】:2023-03-11 11:30:02
【问题描述】:

问题:有时我们会收到(对我们而言)编码无效的链接/短语。

下面的示例和我的第一个解决方案

说明: 我必须在应用程序的一部分中修复无效的编码字符串。有时它是一个单词或短语,但有时也是一个 url。当它是一个 URL 时,我只想更改错误编码的字符。如果我使用 ISO 解码并编码为 UTF-8,则特殊的 url 字符也会被编码(/ : ? = &)。我编写了一个解决方案,该解决方案适用于我的案例,但是您将在下面看到的那些哈希对我来说很难闻。

您是否遇到过类似的问题,或者您知道允许解码除某些字符之外的短语的库吗?像这样的:

decode(String value, char[] ignored)

我也想过将 URL 分解成碎片并仅修复路径和查询,但解析它们等会更加混乱。

TLDR:解码 ISO-8858-1 编码的 URL 并将其编码为 UTF-8。不要触摸 URL 特定字符 (/ ? = : &)

输入/输出示例

// wrong input
"http://some.url/xxx/a/%e4t%fcr%E4/b/%e4t%fcr%E4"
"t%E9l%E9phone"

// good output
"http://some.url/xxx/a/%C3%A4t%C3%BCr%C3%A4/b/%C3%A4t%C3%BCr%C3%A4"
"t%C3%A9l%C3%A9phone"

// very wrong output
"http%3A%2F%2Fsome.url%2Fxxx%2Fa%2F%C3%A4t%C3%BCr%C3%A4%2Fb%2F%C3%A4t%C3%BCr%C3%A4"

我的第一个解决方案

class EncodingFixer {
    private static final String SLASH_HASH = UUID.randomUUID().toString();
    private static final String QUESTION_HASH = UUID.randomUUID().toString();
    private static final String EQUALS_HASH = UUID.randomUUID().toString();
    private static final String AND_HASH = UUID.randomUUID().toString();
    private static final String COLON_HASH = UUID.randomUUID().toString();

    EncodingFixer() {
    }

    String fix(String value) {
        if (isBlank(value)) {
            return value;
        }
        return tryFix(value);
    }

    private String tryFix(String str) {
        try {
            String replaced = replaceWithHashes(str);
            String fixed = java.net.URLEncoder.encode(java.net.URLDecoder.decode(replaced, ISO_8859_1), UTF_8); 
            return replaceBack(fixed);
        } catch (Exception e) {
            return str;
        }
    }

    private String replaceWithHashes(String str) {
        return str
            .replaceAll("/", SLASH_HASH)
            .replaceAll("\\?", QUESTION_HASH)
            .replaceAll("=", EQUALS_HASH)
            .replaceAll("&", AND_HASH)
            .replaceAll(":", COLON_HASH);
    }

    private String replaceBack(String fixed) {
        return fixed
            .replaceAll(SLASH_HASH, "/")
            .replaceAll(QUESTION_HASH, "?")
            .replaceAll(EQUALS_HASH, "=")
            .replaceAll(AND_HASH, "&")
            .replaceAll(COLON_HASH, ":");
    }
}

或者应该更像:???

  1. 检查输入是否为 URL

  2. 创建网址

  3. 获取路径

  4. 按/分割

  5. 修复每个部分
  6. 放回原处
  7. 查询相同,但稍微复杂一点
    ??
    我也考虑过它,但它似乎比上面的那些 replaceAlls 更混乱:/

【问题讨论】:

  • 对 URL 编码最大的误解是它是用来对 URL 进行编码的。它不是。它用于对 URL 的查询参数和路径元素进行编码。我强烈建议您将 URL 拆分为基本 URL、附加路径元素和查询参数并分别处理。
  • 一个好的经验法则是:任何时候你手动编写某种形式的“编码修复”,你可能做错了什么。
  • 很抱歉可能有点迂腐,但您的意思是 ISO-8859-1(请参阅 en.wikipedia.org/wiki/ISO/IEC_8859-1)而不是 ISO-8858-1(iso.org/standard/75885.html),它看起来像是一个特定的 ISO 标准实验室测试的类型(即与字符集无关)?我曾多次遇到定义 8858 的网站,每次都似乎是一个错字。

标签: java encoding utf-8 iso-8859-1


【解决方案1】:

如果您能够清楚地识别出某个字符串是一个 URL,那么在 SO 上的类似问题中关注用户的@jschnasse answer,这可能是您需要的解决方案:

URL url= new URL("http://some.url/xxx/a/%e4t%fcr%E4/b/%e4t%fcr%E4");
URI uri = new URI(url.getProtocol(), url.getUserInfo(), IDN.toASCII(url.getHost()), url.getPort(), url.getPath(), url.getQuery(), url.getRef());
String correctEncodedURL=uri.toASCIIString(); 
System.out.println(correctEncodedURL);

输出: http://some.url/xxx/a/%25e4t%25fcr%25E4/b/%25e4t%25fcr%25E4

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-30
    • 2014-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多