替换通用列表中的两个字节

时间:2013-03-15 12:42:29

标签: c# .net

我希望用{0}替换List<byte>中所有其中一个神奇的2字节包:

  

{0xF8,0x00} - &gt;替换为0xF8
  {0xF8,0x01} - &gt;替换为0xFB
  {0xF8,0x02} - &gt;替换为0xFD
  {0xF8,0x03} - &gt;替换为0xFE

例如:

List<byte> message 
    = new List<byte> { 0xFF, 0xFF, 0xFB, 0xF8, 0x00, 0xF8, 0x01, 0xF8, 0x02, 0xF8, 0x03, 0xFE };

// will be converted to:

List<byte> expected 
    = new List<byte> { 0xFF, 0xFF, 0xFB, 0xF8, 0xFB, 0xFD, 0xFE, 0xFE };

到目前为止,这是我的解决方案,但是我不喜欢它,因为它的可读性非常糟糕:

public static void RemoveEscapeSequences(List<byte> message)
{
    // skipped parameter checks
    for (int index = 0; index < message.Count - 1; ++index)
    {
        if (message[index] == 0xF8)
        {
            // found an escaped byte, look at the following byte to determine replacement
            switch (message[index + 1])
            {
                case 0x0:
                    message[index] = 0xF8;
                    message.RemoveAt(index + 1);
                    break;
                case 0x1:
                    message[index] = 0xFB;
                    message.RemoveAt(index + 1);
                    break;
                case 0x2:
                    message[index] = 0xFD;
                    message.RemoveAt(index + 1);
                    break;
                case 0x3:
                    message[index] = 0xFE;
                    message.RemoveAt(index + 1);
                    break;
            }
        }
    }
}       

是否有更短的解决方案,可读性更高?

4 个答案:

答案 0 :(得分:3)

你可以做这样的事情 - 虽然会稍微慢一些:

public static void RemoveEscapeSequences(List<byte> message)
{
    var replaceBytes = new Dictionary<byte, byte>()
    {
        {0x00, 0xF8}, {0x01, 0xFB}, {0x02, 0xFD}, {0x03, 0xFE}
    };

    // skipped parameter checks
    for (int index = 0; index < message.Count - 1; ++index)
    {
        if (message[index] == 0xF8)
        {
            if(replaceBytes.ContainsKey(message[index + 1]))
            {
                message[index] = replaceBytes[message[index + 1]];
                message.RemoveAt(index + 1);
            }
        }
    }
}  

答案 1 :(得分:2)

您可以使用以下扩展方法:

public static IEnumerable<byte> Escape(this IEnumerable<byte> source)
{
    if (source == null)     
        throw new ArgumentNullException("source");

    using (var enumerator = source.GetEnumerator())
    {
        while (enumerator.MoveNext())
        {
            byte current = enumerator.Current;

            if (current != 0xF8)
            {
                yield return current;
                continue;
            }

            if (!enumerator.MoveNext())
                yield return current;

            byte next = enumerator.Current;

            switch (next)
            {
                case 0x00: yield return 0xF8; break;
                case 0x01: yield return 0xFB; break;
                case 0x02: yield return 0xFD; break;
                case 0x03: yield return 0xFE; break;
                default:
                    yield return current;
                    yield return next;
                    break;
            }
        }
    }
}

用法:

List<byte> result = message.Escape().ToList();

foreach(var b in message.Escape())
     Console.Write("0x{0:x} ", b);

答案 2 :(得分:1)

这是一个非常简单/易懂的版本,也应该是高效的:

private static List<byte> ComputeBytes(List<byte> input)
{
    byte magicValueFirstByte = 0xF8;
    var secondByteToBeReplaced = new List<byte> { 0x00, 0x01, 0x02, 0x03 };
    var replacements = new List<byte> { 0xF8, 0xFB, 0xFD, 0xFE };

    var output = new List<byte>();
    for (int i = 0; i < input.Count; i++)
    {
        var currentValue = input[i];
        if (currentValue == magicValueFirstByte && i < input.Count - 1)
        {
            int index = secondByteToBeReplaced.IndexOf(input[i + 1]);
            if (index >= 0)
            {
                // Then when must replace
                output.Add(replacements[index]);

                // Skip next item
                i++;

                continue;
            }
        }

        // Won't replace value, so add current one
        output.Add(currentValue);
    }

    return output;
}

答案 3 :(得分:1)

为什么不将替换字节放在一个小数组中?

private static byte[] EscapeBytes = new byte[]
{
    /* 0x00 */ 0xF8,
    /* 0x01 */ 0xFB,
    /* 0x02 */ 0xFD,
    /* 0x03 */ 0xFE
};

然后你可以简单地索引数组:

public static List<byte> RemoveEscapeSequences(List<byte> message)
{
    List<byte> result = new List<byte>(message.Count);
    bool escape = false;
    foreach (byte value in message)
    {
        if (escape)
        {
            escape = false;
            // Replace the byte. NOTE 1!
            result.Add(EscapeBytes[value]);
        }
        else if (value == 0xF8)
        {
            // Started an escape sequence.
            escape = true;
        }
        else
        {
            // Just add the byte.
            result.Add(value);
        }
    }
    return result;
}

通过将字节添加到容量已足以保存结果的新列表中,您甚至可以获得更高的性能和更高的可读性。

注1 :当0xF8转义字节后的字节不在0和3之间时,将发生IndexOutOfRangeException。如果你在意,你将不得不添加一个小的检查来查看字节值是否在范围内,并决定如果不是这样做(不替换字节,删除转义,抛出异常)。