Java URLEncoder сохраняет регистр исходного сообщения, но делает код UTF-8 строчными - PullRequest
0 голосов
/ 13 сентября 2018

Я использую URLEncoder.encode (сообщение "UTF-8"); для кодирования строки.

Проблема в том, что мне нужно, чтобы коды UTF-8 в последней строке были строчными, при сохранении регистра исходного сообщения.

Пример:

Сообщение: {Сообщение

Желаемый результат:% 5bMessage

URLEncoder.encode ("{Сообщение", "UTF-8"); ->% 5BСообщение

URLEncoder.encode (сообщение "UTF-8"). ToLowerCase (); ->% 5bssage

Есть ли способ изменить поведение URLEncoder?

или

Существует ли простой способ преобразовать все коды UTF-8 в нижний регистр после факта, для всех символов UTF-8 и для произвольной длины строки?

Ответы [ 3 ]

0 голосов
/ 13 сентября 2018

Проблема в том, что мне нужно, чтобы коды UTF-8 в последней строке были строчными, при сохранении регистра исходного сообщения.

Я предполагаю, что вы хотите, чтобы шестнадцатеричные цифры в escape-числах URL были выражены в нижнем регистре (это не "коды UTF-8"). В любом случае, это неприятная проблема, потому что спецификации для кодирования URL (a.k.a. "процентное кодирование") явно указывают, что шестнадцатеричные цифры в процентных кодах не чувствительны к регистру. Два процента кодированных URL-адресов, которые отличаются только в случае этих шестнадцатеричных цифр, эквивалентны, поэтому код, который обрабатывает их в противном случае, вероятно, будет постоянной проблемой, пока он используется.

Есть ли способ изменить поведение URLEncoder?

Документы java.net.URLEncoder довольно кратки. Не нужно много проверять, чтобы увидеть, что нет, нет механизма для модуляции этого аспекта его поведения. Вы можете написать свою собственную реализацию (это не так сложно), или вы можете найти сторонний кодировщик, но кодировщик стандартной библиотеки не будет удовлетворять вашим требованиям.

Существует ли простой способ преобразовать все коды UTF-8 в нижний регистр после факта, для всех символов UTF-8 и для произвольной длины строки?

Это зависит от того, что вы подразумеваете под "легким". В принципе возможно выполнить такое преобразование, но к тому времени, когда вы анализируете и обновляете закодированный URL-адрес, вы потратили как минимум вдвое больше усилий, чем потребовалось бы для выполнения кодирования так, как вам нужно в первое место.

Но если вы действительно хотите это сделать, то вы можете использовать что-то вроде этого:

import java.util.regex.*;

public class URLRecoder {
    private final static Pattern CODE_PATTERN = Pattern.compile("%[0-9A-Fa-f]{2}");

    /**
     * Recodes a URL-encoded string to ensure that all hex digits in the
     * percent codes that are not decimal digits are expressed in lowercase.
     */
    public String recode(String urlString) {
        StringBuilder sb = new StringBuffer();
        Matcher m = CODER_PATTERN.matcher(urlString);

        while (m.find()) {
            m.appendReplacement(sb, m.group().toLowerCase());
        }
        m.appendTail(sb);

        return sb.toString();
    }
}
0 голосов
/ 14 сентября 2018

Мое решение состояло в том, чтобы скопировать исходный код URLEncoder в новый класс и изменить константу hexStr с "0123456789ABCDEF" на "0123456789abcdef".

Не собираюсь публиковать здесь код из-за возможных проблем с лицензированием:

/*===========================================================================
* Licensed Materials - Property of IBM
 * "Restricted Materials of IBM"
 * 
 * IBM SDK, Java(tm) Technology Edition, v8
 * (C) Copyright IBM Corp. 1995, 2013. All Rights Reserved
 *
 * US Government Users Restricted Rights - Use, duplication or disclosure
 * restricted by GSA ADP Schedule Contract with IBM Corp.
 *===========================================================================
 */
/*
 * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.`

Исходная версия:

 * @version 1.31, 11/17/05
0 голосов
/ 13 сентября 2018

Это жестко запрограммировано в URLEncoder (кстати, я смотрю на Oracle JDK). Преобразование в основном конвертирует вашего персонажа, и получает шестнадцатеричное значение для каждого символа, а затем вычитает разницу между 'a' -'A' (разница символов в верхнем и нижнем регистре в значении), чтобы задать значение в верхнем регистре.

if (Character.isLetter(ch)) {
    ch -= caseDiff;
}

Единственный способ, как я думаю, вы могли бы обойти это, это использовать отражение и изменить значение URLEncoder#caseDiff на 0, поскольку эта переменная является статической конечной:

static final int caseDiff = ('a' - 'A');

сделав что-то вроде (рассмотрите этот псевдо-код. Вы захотите сделать второй проход):

try {
    Field declaredField = URLEncoder.class.getDeclaredField("caseDiff");
    Field modifiersField = Field.class.getDeclaredField("modifiers");

    modifiersField.setAccessible(true);
    modifiersField.setInt(declaredField, declaredField.getModifiers() & ~Modifier.FINAL);
    declaredField.setAccessible(true);
    declaredField.setInt(null, 0);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e1) {
    e1.printStackTrace();
}

На самом деле мне действительно любопытно ваше намерение сделать это, и мне интересно, действительно ли это то, что вы хотите сделать.

...