Uint8 последовательность заполнения с Swift - PullRequest
2 голосов
/ 19 октября 2019

Есть ли способ сделать то, что мы можем легко достичь с помощью to_bytes с python, в Swift?

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

Например, если мне нужно описать число 5 последовательностью из 4 байтов, я должен получить его как \x00\x00\x00\x05.

с помощью функции python to_bytes, которую я могу легко использоватьпервый параметр для определения длины последовательности, и я мог бы написать ее как (5).to_bytes(4, byteorder='big') Я не могу найти способ легко получить тот же результат с помощью swift.

1 Ответ

2 голосов
/ 19 октября 2019

Примечание: Python's to_bytes может принимать любые произвольные length. Если вы хотите преобразовать значение в его собственный размер (например, 1 байт для Int8, 2 байта для Int16, 4 байта для Int32 и т. Д.), Ознакомьтесь с типами числа Swift туда и обратно в/ из данных и Как преобразовать данные в типы типа Doubles, Ints и Strings в Swift?

Для произвольной длины с расширением знака (для отрицательных чисел)Вы можете использовать & 255 для извлечения байта самого низкого порядка и >> 8 для многократного смещения значения вправо на 8 бит в цикле для вычисления байтов. (Здесь я использовал map для генерации массива байтов). Затем используйте reversed(), чтобы поместить их в нужный порядок байтов :

var i = 5
let len = 4

let arr: [UInt8] = (0..<len).map { _ in
    let byte = UInt8(i & 255)
    i >>= 8
    return byte }
    .reversed()

print(arr)

Выход:

[0, 0, 0, 5]

Примечания:

  • >>= расширит знак отрицательное число, поэтому -5 даст ожидаемый результат дополнения до 2: [255, 255, 255, 251].
  • Явный ввод arr как [UInt8] гарантирует, что arr равен [UInt8], а не ReversedCollection<Array<UInt8>> и , это помогает Swift в определении типа возврата map.
  • Для порядка little endian удалите reversed() и просто используйте результат map.

Реализация toBytes(length:bigEndian:) как extension из Int:

Это можно добавить как расширение к Int, чтобы дополнительно имитировать поведение метода to_bytes Python:

extension Int {
    func toBytes(length: Int, bigEndian: Bool = true) -> [UInt8] {
        var i = self
        let bytes: [UInt8] = (0..<length).map { _ in
            let byte = UInt8(i & 255)
            i >>= 8
            return byte
        }

        return bigEndian ? bytes.reversed() : bytes
    }
}

Примеры:

print(5.toBytes(length: 4))
[0, 0, 0, 5]
print((-5).toBytes(length: 4))
[255, 255, 255, 251]
print(5.toBytes(length: 8))
[0, 0, 0, 0, 0, 0, 0, 5]
print(5.toBytes(length: 8, bigEndian: false))
[5, 0, 0, 0, 0, 0, 0, 0]

Расширение toBytes для работы с любым Int типом

Просто безстремление FixedWidthInteger вместо Int делает эту работу для всех типов Int и UInt, за исключением Int8, который неправильно обрабатывает расширение знака. Явная проверка этого типа и преобразование его в Int решает эту проблему.

extension FixedWidthInteger {
    func toBytes(length: Int, bigEndian: Bool = true) -> [UInt8] {
        if self is Int8 {
            return Int(self).toBytes(length: length, bigEndian: bigEndian)
        }

        var i = self
        let bytes: [UInt8] = (0..<length).map { _ in
            let byte = UInt8(i & 255)
            i >>= 8
            return byte
        }

        return bigEndian ? bytes.reversed() : bytes
    }
}

Примеры:

print(Int8(-5).toBytes(length: 10))
print(Int16(-5).toBytes(length: 10))
print(Int32(-5).toBytes(length: 10))
print(Int64(-5).toBytes(length: 10))
[255, 255, 255, 255, 255, 255, 255, 255, 255, 251]
[255, 255, 255, 255, 255, 255, 255, 255, 255, 251]
[255, 255, 255, 255, 255, 255, 255, 255, 255, 251]
[255, 255, 255, 255, 255, 255, 255, 255, 255, 251]
print(Int8(5).toBytes(length: 10))
print(Int16(5).toBytes(length: 10))
print(Int32(5).toBytes(length: 10))
print(Int64(5).toBytes(length: 10))
print(UInt8(5).toBytes(length: 10))
print(UInt16(5).toBytes(length: 10))
print(UInt32(5).toBytes(length: 10))
print(UInt64(5).toBytes(length: 10))
[0, 0, 0, 0, 0, 0, 0, 0, 0, 5]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 5]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 5]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 5]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 5]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 5]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 5]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 5]
print(UInt64.max.toBytes(length: 10))
[0, 0, 255, 255, 255, 255, 255, 255, 255, 255]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...