Удаление ведущих нулей в массиве байтов - PullRequest
3 голосов
/ 09 мая 2020

У меня есть следующий массив байтов -

byte[] arrByt = new byte[] { 0xF, 0xF, 0x11, 0x4 };

поэтому в двоичном формате arrByt = 00001111 00001111 00010001 000000100

Теперь я хочу создать новый массив байтов, удалив ведущие нули для каждого байта из arrByt

arrNewByt = 11111111 10001100 = { 0xFF, 0x8C };

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

Есть ли более быстрый способ добиться этого (например, логические операции, битовые операции или другие эффективные способы)?

Спасибо.

Ответы [ 3 ]

1 голос
/ 09 мая 2020

Это должно сделать работу довольно быстро. По крайней мере, только стандартные циклы и операторы. Попробуйте, он также подойдет для более длинных исходных массивов.

// source array of bytes
var arrByt = new byte[] {0xF, 0xF, 0x11, 0x4 };

// target array - first with the size of the source array
var targetArray = new byte[arrByt.Length];

// bit index in target array
// from left = byte 0, bit 7 = index 31; to the right = byte 4, bit 0 = index 0
var targetIdx = targetArray.Length * 8 - 1;

// go through all bytes of the source array from left to right
for (var i = 0; i < arrByt.Length; i++)
{
    var startFound = false;

    // go through all bits of the current byte from the highest to the lowest
    for (var x = 7; x >= 0; x--)
    {
        // copy the bit if it is 1 or if there was already a 1 before in this byte
        if (startFound || ((arrByt[i] >> x) & 1) == 1)
        {
            startFound = true;

            // copy the bit from its position in the source array to its new position in the target array
            targetArray[targetArray.Length - ((targetIdx / 8) + 1)] |= (byte) (((arrByt[i] >> x) & 1) << (targetIdx % 8));

            // advance the bit + byte position in the target array one to the right
            targetIdx--;
        }
    }
}

// resize the target array to only the bytes that were used above
Array.Resize(ref targetArray, (int)Math.Ceiling((targetArray.Length * 8 - (targetIdx + 1)) / 8d));

// write target array content to console
for (var i = 0; i < targetArray.Length; i++)
{
    Console.Write($"{targetArray[i]:X} ");
}

// OUTPUT: FF 8C
0 голосов
/ 09 мая 2020

Пожалуйста, проверьте этот фрагмент кода. Это может вам помочь.

        byte[] arrByt = new byte[] { 0xF, 0xF, 0x11, 0x4 };
        byte[] result = new byte[arrByt.Length / 2];

        var en = arrByt.GetEnumerator();

        int count = 0;
        byte result1 = 0;
        int index = 0;
        while (en.MoveNext())
        {
            count++;
            byte item = (byte)en.Current;

            if (count == 1)
            {
                while (item < 128)
                {
                    item = (byte)(item << 1);
                }
                result1 ^= item;
            }

            if (count == 2)
            {
                count = 0;
                result1 ^= item;

                result[index] = result1;
                index++;
                result1 = 0;
            }
        }

        foreach (var s in result)
        {
            Console.WriteLine(s.ToString("X"));
        }
0 голосов
/ 09 мая 2020

Если вы пытаетесь найти расположение наиболее значимого бита, вы можете выполнить log2 () байта (а если у вас нет log2, вы можете использовать log (x) / log (2) что то же самое, что и log2 (x))

Например, числа 7, 6, 5 и 4 имеют «1» в позиции 3-го бита (0111, 0110, 0101, 0100). Log2 () из них все от 2 до 2,8. То же самое происходит со всем, что находится в 4-м бите, это будет число от 3 до 3,9. Таким образом, вы можете определить наиболее значимый бит, добавив 1 к log2 () числа (округлить в меньшую сторону).

floor(log2(00001111)) + 1 == floor(3.9) + 1 == 3 + 1 == 4

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

int numToShift = 8 - floor(log2(bytearray[0])) + 1;
shiftedValue = bytearray[0] << numToShift;

Оттуда, это просто вопрос отслеживания того, сколько битов (еще не помещенных в массив байтов) у вас есть, а затем выдвинуть некоторые / все из них on.

Приведенный выше код будет работать только для первого байтового массива. Если вы поместите это в al oop, numToShift, возможно, потребуется отслеживать последний пустой слот для переноса вещей (возможно, вам придется сдвинуть вправо, чтобы соответствовать текущему массиву байтов, а затем использовать остатки для помещения в начало следующего байтового массива). Поэтому вместо того, чтобы делать «8 -» в приведенном выше коде, вы могли бы указать начальное местоположение. Например, если бы для заполнения текущего массива байтов осталось всего 3 бита, вы бы сделали:

int numToShift = 3 - floor(log2(bytearray[0])) + 1;

Таким образом, это число должно быть переменной:

int numToShift = bitsAvailableInCurrentByte - floor(log2(bytearray[0])) + 1;
...