Java urlencoder сохраняет регистр исходного сообщения, но делает код utf-8 строчными

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

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

Пример:

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

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

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

URLEncoder.encode (сообщение, «UTF-8»). ToLowerCase (); ->% 5bсообщение

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

или

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

0
0
952
3

Ответы 3

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

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

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

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();
}

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

Я полностью скопировал исходный код URLEncoder в новый класс и изменил caseDiff = 0. Он ничего не сделал. caseDiff фактически нигде в URLEncoder не используется.

Spinnernicholas 14.09.2018 01:24

Это не правда. Я могу сказать вам прямо сейчас, что в Java 1.8.80 он используется в строках 276 и 281.

searchengine27 14.09.2018 20:23

Я выполнил именно то, что вы утверждаете, и получаю строчные шестнадцатеричные числа.

searchengine27 14.09.2018 20:37

The problem is that I need the UTF-8 codes in the final string to be lower case, while maintaining the case of the original message.

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

Is there a way to change the behavior of URLEncoder?

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

Is there an easy way to convert all the UTF-8 codes to lower case after the fact, for all UTF-8 characters and for arbitrary string length?

Это зависит от того, что вы подразумеваете под словом «легкий». В принципе возможно выполнить такое преобразование, но к тому времени, когда вы анализируете и обновляете закодированный 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) {
        StringBuffer sb = new StringBuffer();
        Matcher m = CODE_PATTERN.matcher(urlString);

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

        return sb.toString();
    }
}

Мое решение заключалось в том, чтобы скопировать исходный код 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

Другие вопросы по теме