Проблема в том, что мне нужно, чтобы коды 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();
}
}