十六进制与字符串互转

JAVA HEX BINARY STRING

Posted by gomyck on January 10, 2023

2023 第一行代码, 由于分析了一波数据包组成, 想着如何把网络数据包中的 16 进制编码转成明文, 于是有了下面的工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package com.gomyck.util;

import java.nio.charset.StandardCharsets;

/**
 * 16进制字符串与字符串互转工具类
 *
 * 按字节进行 16 进制与 2 进制转换就是  一字节8位  转  两位0~F
 * 每个字节分两次 从中间切割为左右各四位  转换成十六进制
 * 右侧四位不需要偏移四位, 因为本身这四位就没超过16 (最大 15 2^4-1)
 * 左侧四位需要向右偏移 4 位, 也就是除以 16(左侧四位肯定是 16 的倍数) 16 32 48 ....
 * 然后把值  按照 0~F 从左到右拼接起来, 比如 0x12 就是 十进制的18  对应的二进制就是  0b0001 0010
 * 转换关系如下:
 * System.out.println((0b00010010 & 0x0f0) >> 4); //结果为1 计算左侧四位对应的 16 进制数
 * System.out.println((0b00110010 & 0x0f));       //结果为2 计算右侧四位对应的 16 进制数
 *
 * Unicode 是咋回事儿?
 * Unicode 是一种字符集, 每个字符再这个集合里, 有固定的标识(ID)
 * exp: (U+0041 65:A) (U+005A 90:Z) (U+0061 97:a)  (U+007A 122:z)
 * 去 https://www.unicode.org/charts/ 这里可以查看
 * 或 https://www.unicode.org/charts/charindex.html 搜索 chinese 可以查看中文编码表
 * 实际上 Unicode 最终也会根据 16 进制的标识转换成 2 进制, 用以被计算机识别, 并最终展示到终端
 * 数据与指令 - CPU(字体引擎处理, 每个字的 RGB) - 显卡驱动程序 - 显卡(GPU) - 显示器 - 人眼
 *
 * @author gomyck
 * --------------------------------
 * | qq: 474798383                 |
 * | email: [email protected]   |
 * | blog: https://blog.gomyck.com |
 * --------------------------------
 * @version [1.0.0]
 * @since 2023/1/10
 */
public class HexUtil {

    public final static String HEX_DIC = "0123456789ABCDEF";

    /**
     * 十六进制字符串转字符串
     *
     * @param hexStr 十六进制字符串
     * @param delimiter 分隔符
     * @return 字符串
     */
    public static String hex2String(String hexStr, String delimiter) {
        if (ObjectJudge.isNull(hexStr)) return null;
        if (delimiter == null) delimiter = "";
        hexStr = hexStr.toUpperCase();
        hexStr = hexStr.replaceAll(delimiter, "");
        char[] hexChars = hexStr.toCharArray();
        byte[] strBytes = new byte[hexStr.length() / 2];
        int hexNum;
        for (int i = 0; i < strBytes.length; i++) {
            hexNum = HEX_DIC.indexOf(hexChars[2 * i]) * 16;
            hexNum += HEX_DIC.indexOf(hexChars[2 * i + 1]);
            strBytes[i] = (byte) (hexNum & 0xff);
        }
        return new String(strBytes, StandardCharsets.UTF_8);
    }

    /**
     * 字符串转换成十六进制字符串
     *
     * @param str 字符串
     * @param delimiter 分隔符
     * @return 十六进制字符串
     */
    public static String string2Hex(String str, String delimiter) {
        if (ObjectJudge.isNull(str)) return null;
        if (ObjectJudge.isNull(delimiter)) delimiter = "";
        char[] hexCharsDic = HEX_DIC.toCharArray();
        StringBuilder sb = new StringBuilder();
        byte[] strBytes = str.getBytes();
        int hexIndex;
        for (int i = 0; i < strBytes.length; i++) {
            hexIndex = (strBytes[i] & 0x0f0) >> 4;
            sb.append(hexCharsDic[hexIndex]);
            hexIndex = strBytes[i] & 0x0f;
            sb.append(hexCharsDic[hexIndex]);
            if (i != strBytes.length - 1) sb.append(delimiter);
        }
        return sb.toString()
                 .trim();
    }
}