c#左移半字节在一个字节数组中

时间:2012-07-13 17:58:48

标签: c# bytearray bit-manipulation

以下是我的功能要求:

取以下字符串:

6900460420006149231=13050010300100000

并将其转换为以下字节数组:

{ 0x37, 0x06, 0x90, 0x04, 0x60, 0x42, 0x00, 0x06, 0x14, 0x92, 0x31, 0xD1, 0x30, 0x50, 0x01, 0x03, 0x00, 0x10, 0x00, 0x00 }

第一个字节0x37是二进制字符串的原始长度。接下来的10个字节是以bcd格式编码的字符串“6900460420006149231”。这是变得棘手的地方。现在我需要Hex'D'来表示两个字段之间的分隔符(=)。您可以在字节数组中看到12索引的高半字节中的十六进制。字节数组的其余部分是以bcd格式编码的第二个字段“13050010300100000”。如果原始长度是奇数,我将前导零填充到未使用数据的前半个字节。

我不希望任何人完全实施,所以让我们分解并解决我遇到麻烦的地方。 让我们说:

byte[] field1Bytes = { 0x06, 0x90, 0x04, 0x60, 0x42, 0x00, 0x06, 0x14, 0x92, 0x31 }
byte[] field2Bytes = { 0x01, 0x30, 0x50, 0x01, 0x03, 0x00, 0x10, 0x00, 0x00 }
byte separator = 13; // D  0x0D

如果我只使用Array.Copy,我最终会得到:

{ 0x06, 0x90, 0x04, 0x60, 0x42, 0x00, 0x06, 0x14, 0x92, 0x31, 0x0D, 0x01, 0x30, 0x50, 0x01, 0x03, 0x00, 0x10, 0x00, 0x00 }

上面的字节数组并不是我所需要的..任何关于如何实现以下函数的想法让我更接近我想要实现的目标:

byte[] ShiftLeftAndCombine(byte[] b1, byte[] b2)

,其中

ShiftLeftAndCombine({0x0d}, {0x01, 0x30})

将返回

{0xd1, 0x30}
  • 在旁注上我意识到我需要处理偶数/奇数字段长度以解决我正在写的实际功能,但让我担心=]

5 个答案:

答案 0 :(得分:1)

你真正需要做的是将整个第二块内存移到四位,在我看来。这意味着你将做的不仅仅是复制,你将把字节n + 1的“前导”(最高有效)位移到“尾随”(最低有效)第n个字节。这是一个字节数组的通用“位移位器”。

    byte[] shiftBlock(byte[] bytes, short bitShift)
    {
        byte[] newBytes = new byte[bytes.Length+1];
        for (int index=0;index < bytes.Length; index++)
        {
            // Each new byte is the current byte shifted left by "bitShift" bits,
            // followed by the first 8-bitShift bits of the next byte OR zero,
            // if we're at the end of the array. Shift the next-bytes bits to
            // the right, and OR the result together. 

            byte newByteMSB = (byte)(bytes[index] << bitShift); // shift left bitShift bits
            byte newByteLSB = (byte)((index==bytes.Length-1)?((byte)0):(bytes[index+1]));
            newByteLSB = (byte) (newByteLSB >> (8-bitShift));

            newBytes[index] = (byte) ( newByteMSB | newByteLSB);

        }

        return newBytes;
    }

您应该能够根据必要的警告将其调整为更广泛的解决方案。我给它一个粗略的测试,它似乎适用于我抛出的简单字节数组。希望这有帮助!

答案 1 :(得分:0)

不确定这是否是作业,但左移和合并部分看起来像这样:

var pos = 0;
var newByte = b1[pos] << 4;
newByte |= b2[pos]

显然你会想要在一个循环中这样做,并考虑到2个数组的长度

答案 2 :(得分:0)

编辑修改为不在结果中包含原始长度。

希望这会有所帮助。但是,不知道如何计算原始长度的值为0x37。 :)

根据所述的预期结果,您只需将分隔符nybble转换为第二个数组的第一个字节。

byte[] field1Bytes = { 0x06, 0x90, 0x04, 0x60, 0x42, 0x00, 0x06, 0x14, 0x92, 0x31 } ;
byte[] field2Bytes = { 0x01, 0x30, 0x50, 0x01, 0x03, 0x00, 0x10, 0x00, 0x00 } ;
byte separator = 13; // D  0x0D 

byte[] result = new byte[field1Bytes.Length + field2Bytes.Length];


Array.Copy(field1Bytes, 0, result, 0, field1Bytes.Length);
Array.Copy(field2Bytes, 0, result, field1Bytes.Length, field2Bytes.Length);

// shift the separator into the first byte of the second array in the result
result[field1Bytes.Length] |= (byte)(separator << 4);

这会产生:

0x06 0x90 0x04 0x60 0x42 0x00 0x06 0x14 0x92 0x31 0xd1 0x30 0x50 0x01 0x03 0x00 0x10 0x00 0x00

...符合规定的预期结果。

答案 3 :(得分:0)

我会做一个BCD课。然后BCD.ToByteArray()将以Byte []格式给出BCD的当前表示,BCD.ToString()将给出字符串格式。内部存储BCD作为每个BCD数字的一个数组元素。如果你设计自己的数据结构而不是试图让Byte []做你不打算做的事情,你会更好。

答案 4 :(得分:0)

好的,我明白了:

    static void Main(string[] args)
    {
        const string rawTrack = "6900460420006149231=13050010300100000";

        var byteList = new LinkedList<byte>();

        foreach (var c in rawTrack)
        {
            if(c.Equals('='))
            {
                byteList.AddLast(13);
                continue;
            }

            var bytes = Formatters.Bcd.GetBytes(new string(c, 1));  // for 9 gives 0x09
            byteList.AddLast(bytes[0]);
        }

        // Adjust Buffer if odd length
        if(rawTrack.Length % 2 != 0)
        {
            byteList.AddFirst(0);
        }

        var result = new byte[byteList.Count / 2];
        var buffer = new byte[byteList.Count];
        byteList.CopyTo(buffer, 0);

        var j = 0;
        for(var i = 0; i < buffer.Length - 1; i += 2, j++ )
        {
            result[j] = CombineLowNibble(buffer[i], buffer[i + 1]);
        }


        Console.WriteLine(BitConverter.ToString(result));
    }

    private static byte CombineLowNibble(byte b, byte b1)
    {
        return (byte) ((b << 4) | b1);
    }

结果如下:

06-90-04-60-42-00-06-14-92-31-D1-30-50-01-03-00-10-00-00