ISO-8858-1 до UTF-8 только в URL, только недопустимые символы - PullRequest
0 голосов
/ 10 марта 2020

Проблема : иногда мы получаем ссылки / фразы с недопустимой (для нас) кодировкой.

Примеры и мое первое решение ниже

Описание : Я должен исправить недопустимые закодированные строки в одной части приложения. Иногда это слово или фраза, а иногда и URL. Когда это URL, я хотел бы изменить только неправильно закодированные символы. Если я декодирую с ISO и кодирую в UTF-8, специальные символы URL также кодируются (/:? = &). Я кодировал решение, которое отлично работает для моих дел, но те хеши, которые вы увидите ниже, плохо пахнут для меня.

У вас была похожая проблема или вы знаете библиотеку, которая позволяет декодировать фразу, кроме некоторых символов? Примерно так:

decode(String value, char[] ignored)

Я также хотел бы разбить URL на части и исправить только путь и запрос, но было бы еще больше беспорядка при их разборе и т. Д. c ..

TLDR : декодировать URL-адрес в кодировке ISO-8858-1 и кодировать его в UTF-8. Не прикасайтесь к указанным URL-адресам c символов (/ ? = : &)

Примеры ввода / вывода :

// 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. Создать URL

  3. Получить путь

  4. Разделить на /

  5. Исправить каждую часть
  6. Сложите это вместе
  7. То же самое для запроса, но немного сложнее
    ??
    Я тоже об этом, но это кажется еще более грязным, чем те, что replaceAll выше: /

1 Ответ

0 голосов
/ 10 марта 2020

Если вы в состоянии четко распознать, что какая-то строка является URL-адресом, то после @jschnasse пользователя ответ на аналогичный вопрос по SO, это может быть решением, которое вам нужно:

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

...