字节数组中的c#左移位半字节

字节数组中的c#左移位半字节,c#,bytearray,bit-manipulation,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格式编码的字符串“6900460

以下是我的职能要求:

以以下字符串为例:

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”。这就是问题的症结所在。现在我需要十六进制'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)
在哪里

会回来吗

{0xd1, 0x30}
  • 另一方面,我意识到我需要处理偶数/奇数字段长度来处理我正在编写的实际函数,但让我担心一下=]

不确定这是否是作业,但左移和联合收割机部分的外观如下:

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

var newByte=b1[pos]编辑:修改为不在结果中包含原始长度

希望这有帮助。但不确定如何计算原始长度,使其值为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);

。。。符合所述的期望结果。

我将创建一个BCD类。然后BCD.ToByteArray()将以字节[]格式提供BCD的当前表示形式,BCD.ToString()将提供字符串格式。在内部将BCD存储为每个BCD数字一个数组元素。如果您设计自己的数据结构,而不是试图让Byte[]做它不打算做的事情,您会过得更好。

好的,我明白了:

    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);
    }

在我看来,你真正需要做的是将整个第二块内存左移四位。这意味着您要做的不仅仅是复制,而是将字节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;
    }
byte[]shiftBlock(byte[]bytes,短位移位)
{
字节[]新字节=新字节[字节.长度+1];
for(int index=0;index(8位移位));
新字节[索引]=(字节)(新字节msb |新字节lsb);
}
返回新细胞;
}

您应该能够通过必要的警告将其应用到更广泛的解决方案中。我对它进行了粗略的测试,它似乎可以处理我抛出的简单字节数组。希望这有帮助

不,是工作。我得到了报酬……哈哈,好吧,我不确定,因为这听起来像是一个家庭作业问题!:)我下面的答案是假设作业,如果你需要,我会更新它…左移位运算符不需要是4,而不是1吗?是4。我将给出正确的答案,但我现在将使用一个不同的实现,完成后将与大家分享。基本上,我将把字符串中的每个字符视为一个字节{0x06,0x09,0x00,0x04,0x06,0x00,0x00,0x00,0x06,0x01,0x04,0x09,0x02,0x03,0x01,0x0D,0x01,0x03,0x00,0x05,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00},然后combine@aelstonjones好的,很好,我想看看您是如何实现它的。这不会像我认为OP的意图那样将field2Byte数组向左移动-只是操作员…假设我正确地解释了OP的问题:)@DavidW输出似乎与他期望的输出匹配。根据他的期望结果,只有第二个数组的第一个字节需要将分隔符值移入。第二个数组的值根本不需要改变。嗯……明白你的意思,门罗,但现在我要恭敬地表示不同意。如果这一点是“打包”两个字节数组,中间的0xD“夹心”,那么在我看来,你必须考虑把第二个数组的四位的内容左移,或者当你解码信息时,你会引入四个错误的零位。也许错了,谁知道呢:)@DavidW刚刚偏离了他所说的结果。如果第二个数组的第一个字节>=0x80,那么肯定会有一些wierd结果。但在这种情况下,您似乎希望将第二个数组右移四位,以保护第一个字节的上nybble不丢失。我想OP是用“左移”这个词来描述分隔符是如何处理的,然后事情就从这里混为一谈了。但是如果没有OP的更多反馈,这一点是模棱两可的。同意,梦露,但他的问题似乎已经解决了。但这种比特转换代码可能有一天会派上用场:)祝福…谢谢大卫,我刚刚解决了我的函数,但我会把它书签起来,以备下次使用=]干得好!如果您可以将值放入字节数组
field1Bytes
field2Bytes
,那么您会发现我的答案执行速度更快。但是,如果您对解决方案的性能感到满意,那就去做吧!如果您处理的是较小的长度,那么您会发现
列表
将比
链接列表
快得多。我首先需要添加链接列表。感谢您的回答
列表。插入(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
    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;
    }