Kotlin将十六进制字符串转换为字节数组

32

我有这个字符串:

val s = "00b44a0bc6303782b729a7f9b44a3611b247ddf1e544f8b1420e2aae976003219175461d2bd7" +
        "6e64ba657d7c9dff6ed7b17980778ec0cbf75fc16e52463e2d784f5f20c1691f17cdc597d7a514108" +
        "0809a38c635b2a62082e310aa963ca15953894221ad54c6b30aea10f4dd88a66c55ab9c413eae49c0b" +
        "28e6a3981e0021a7dcb0759af34b095ce3efce78938f2a2bed70939ba47591b88f908db1eadf237a7a" +
        "7100ac87130b6119d7ae41b35fd27ff6021ac928273c20f0b3a01df1e6a070b8e2e93b5220ad0210400" +
        "0c0c1e82e17fd00f6ac16ef37c3b6153d348e470843a84f25473a51f040a42671cd94ffc989eb27fd42" +
        "b817f8173bfa95bdfa17a2ae22fd5c89dab2822bcc973b5b90f8fadc9b074cca8f9365b1e8994ff0bda48" +            "b1f7498cce02d4e794915f8a4208de3eaf9fbff5"

这是硬编码为字符串格式的字节的十六进制表示法。我需要将其作为字节数组,重要的是,不是其ASCII表示形式,而是它所代表的十六进制值。

所有我能找到的Kotlin方法,例如:

val b = s.encodeToByteArray()

似乎正在获取字符串的实际ASCII值,并将其转换为字节数组。

如何直接从这个字符串中创建字节数组?


如果字符串具有奇数个十六进制数字,应该发生什么?它应该假定前导零吗?(还是后置零?) - gidds
2
我希望这个十六进制不是某种加密货币的私钥;-) - georgiecasey
3个回答

74

你可以像这样处理:

fun String.decodeHex(): ByteArray {
    check(length % 2 == 0) { "Must have an even length" }

    return chunked(2)
        .map { it.toInt(16).toByte() }
        .toByteArray()
}
  1. 将字符串拆分为两个字符的一对,表示每个字节。
  2. 解析每个十六进制数对为它们的整数值。
  3. 将解析后的整数转换为Bytes

这是一个非常优雅的方法,正如预期的那样有效。不错! - mcy

14

我的另一个答案是最简单的方法,但它在创建字节数组之前会创建两个中间列表 - 一个字符串列表和一个字节列表。这里有两个稍微复杂一些的版本,它们更有效率。


这个版本使用序列来利用惰性求值。它仍然为每个字节生成一个字符串,但不使用任何中间列表。

fun String.decodeHex(): ByteArray {
    check(length % 2 == 0) { "Must have an even length" }

    val byteIterator = chunkedSequence(2)
        .map { it.toInt(16).toByte() }
        .iterator()

    return ByteArray(length / 2) { byteIterator.next() }
}

这个版本使用了 JDK 的 java.lang.Integer.parseInt 函数。它直接创建 ByteArray,没有中间数据结构。

fun String.decodeHex(): ByteArray {
    check(length % 2 == 0) { "Must have an even length" }

    return ByteArray(length / 2) {
        Integer.parseInt(this, it * 2, (it + 1) * 2, 16).toByte()
    }
}

2
Kotlin 1.9引入了实验性的fun String.hexToByteArray(): ByteArray
可以按照以下方式使用:
@OptIn(ExperimentalStdlibApi::class)
val byteArray = "16665373b6bf396f75914a0bed297d44".hexToByteArray()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接