Java实现Torrent Info Hash的URL编码问题求助
解决Torrent Info Hash的URL编码问题
需求明确:将十六进制格式的info hash(如0a85522a2f09e42f3d63a89a0d45e4589f8b904c)转换为目标URL编码格式(如%0a%85R%2a%2f%09%e4%2f%3dc%a8%9a%0dE%e4X%9f%8b%90L),且不依赖第三方库。
原代码的核心问题
你的代码逻辑完全偏离了正确路径:
- 错误地将十六进制字符串直接按UTF-8转字节,而非把十六进制解析为info hash的原始字节数组
- 遍历单个十六进制字符单独编码,导致每个字符(比如
R)被错误拆分处理,而非对应原始字节的编码
正确实现思路
- 十六进制转原始字节数组:每两个十六进制字符对应一个字节(如
0a转0x0A,52转0x52即ASCII字符R) - 字节级URL编码:
- 若字节对应可打印且非URL保留的ASCII字符,直接保留原字符
- 其余情况(不可打印ASCII、URL保留字符)转换为
%XX格式,XX为字节的两位小写十六进制
完整代码实现
import java.nio.charset.StandardCharsets; public class InfoHashUrlEncoder { public static void main(String[] args) { String hexInfoHash = "0a85522a2f09e42f3d63a89a0d45e4589f8b904c"; String encoded = encodeInfoHash(hexInfoHash); System.out.println(encoded); // 输出: %0a%85R%2a%2f%09%e4%2f%3dc%a8%9a%0dE%e4X%9f%8b%90L } public static String encodeInfoHash(String hexInfoHash) { // 校验十六进制字符串长度是否为偶数 if (hexInfoHash.length() % 2 != 0) { throw new IllegalArgumentException("无效的十六进制info hash长度"); } byte[] rawHash = new byte[hexInfoHash.length() / 2]; // 把十六进制字符串转换为原始字节数组 for (int i = 0; i < hexInfoHash.length(); i += 2) { String hexPair = hexInfoHash.substring(i, i + 2); rawHash[i / 2] = (byte) Integer.parseInt(hexPair, 16); } StringBuilder encoded = new StringBuilder(); for (byte b : rawHash) { int unsignedByte = b & 0xFF; // 转换为无符号字节值,避免负数问题 // 判断是否为可打印且非URL保留的ASCII字符 if ((unsignedByte >= 32 && unsignedByte <= 126) && !isUrlReservedChar((char) unsignedByte)) { encoded.append((char) unsignedByte); } else { // 转换为%XX小写格式,不足两位补0 encoded.append('%'); if (unsignedByte < 16) { encoded.append('0'); } encoded.append(Integer.toHexString(unsignedByte).toLowerCase()); } } return encoded.toString(); } // 判断是否为RFC 3986定义的URL保留字符 private static boolean isUrlReservedChar(char c) { return switch (c) { case ':', '/', '?', '#', '[', ']', '@', '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=' -> true; default -> false; }; } }
代码关键点说明
- 十六进制转字节:通过每两位截取字符串,用
Integer.parseInt解析为十六进制数值后强制转成byte - 无符号字节处理:用
b & 0xFF把字节转成0-255的整数,避免Java字节默认带符号导致的负数问题 - URL保留字符校验:严格遵循RFC 3986标准,确保这些特殊字符被正确编码
内容的提问来源于stack exchange,提问作者Madman
相关产品推荐
相关产品推荐

