Преобразование массива байтов в шестнадцатеричную строку

Удивительно (для меня), этот код не делает то, что я хочу:

fun ByteArray.toHexString() : String {
    return this.joinToString("") { it.toString(16) }
}

Оказывается, Byte подписано, поэтому вы получаете отрицательные шестнадцатеричные представления для отдельных байтов, что приводит к совершенно ложному конечному результату.

Кроме того, Byte.toString не будет добавлять начальные нули, которые вам здесь нужны.

Что самое простое (без дополнительных библиотек, в идеале без расширений) соотв. самое эффективное исправление?


person Raphael    schedule 07.09.2018    source источник
comment
... можете ли вы дать мне ввод, для которого вы получаете поддельный вывод?   -  person Roland    schedule 07.09.2018
comment
@Роланд 0xFF.toByte().toString(16)   -  person Moira    schedule 07.09.2018
comment
@Roland Мой намек на то, что я видел - в хэшах SHA-256.   -  person Raphael    schedule 07.09.2018
comment
попробовал все однобайтовые строки от 0x00 до 0xFF. Все варианты на этой странице дают одинаковый результат... что мне здесь не хватает?   -  person Roland    schedule 07.09.2018
comment
просто интересно: как вы получаете свой ByteArray?   -  person Roland    schedule 07.09.2018
comment
@Roland Преобразовал строки UTF-8 в ByteArray, подверг их хэшированию и шифрованию (отдельно) с помощью BouncyCastle. Невозможно воспроизвести без криптоэлементов, да.   -  person Raphael    schedule 07.09.2018


Ответы (4)


Поскольку я работаю на Kotlin 1.3, вас также может заинтересовать UByte в ближайшее время (обратите внимание, что это экспериментальная функция. См. также Kotlin 1.3M1 и объявление 1,3м2)

E.g.:

@ExperimentalUnsignedTypes // just to make it clear that the experimental unsigned types are used
fun ByteArray.toHexString() = asUByteArray().joinToString("") { it.toString(16).padStart(2, '0') }

Параметр форматирования, вероятно, самый приятный из других вариантов (но, возможно, не так легко читается... и я всегда забываю, как он работает, поэтому его определенно не так легко запомнить (для меня :-)):

fun ByteArray.toHexString() = joinToString("") { "%02x".format(it) }
person Roland    schedule 07.09.2018
comment
Если кому-то нужна версия, не предназначенная для JVM: fun ByteArray.toHexString() = joinToString("") { (0xFF and it.toInt()).toString(16).padStart(2, '0') } - person Sven; 20.09.2019
comment
Вы великий человек! - person Burf2000; 29.06.2021

printf делает то, что мы хотим здесь:

fun ByteArray.toHexString() : String {
    return this.joinToString("") {
        java.lang.String.format("%02x", it)
    }
}
person Raphael    schedule 07.09.2018
comment
Сомневаюсь, что вам нужно расшифровывать java.lang.String - person msrd0; 08.09.2018
comment
@ msrd0 В вопросе нет тега Java. Используя KotlinJS, я могу оценить, когда могу исключить такой ответ с первого взгляда. - person Zackline; 05.11.2018
comment
@ msrd0 Думаю, я хотел убедиться, что не выбрал Kotlin String, но это действительно кажется ненужным. - person Raphael; 06.11.2018
comment
@Zackline Интересный момент. Появилось ли какое-либо соглашение для пометки вопросов Kotlin, касающихся JVM/JS/Android/Native? - person Raphael; 06.11.2018

На этот вопрос был дан ответ, но форматирование мне не понравилось. Вот что-то, что форматирует его во что-то более читаемое... по крайней мере, для меня.

@JvmOverloads
fun ByteArray.toHexString(separator: CharSequence = " ",  prefix: CharSequence = "[",  postfix: CharSequence = "]") =
    this.joinToString(separator, prefix, postfix) {
        String.format("0x%02X", it)
    }

выход:

[0x10 0x22]
person JPM    schedule 07.05.2020

fun ByteArray.toHexString() = joinToString("") {
    Integer.toUnsignedString(java.lang.Byte.toUnsignedInt(it), 16).padStart(2, '0')
}

К счастью, в Java есть toUnsignedString методов для Integer и Long. К сожалению, эти методы только для Integer и Long, поэтому вам нужно сначала преобразовать каждый байт (используя Byte#toUnsignedInt).

person Moira    schedule 07.09.2018
comment
Любая причина для понижения? Хотя теперь доступны лучшие методы, встроенные в Kotlin, это все еще правильно и эффективно (для Kotlin/JVM). - person Moira; 11.08.2020