7

我想用一个字节替换我中那些神奇的 2 字节包中的List<byte>每一个:

{ 0xF8, 0x00 } -> 替换为 0xF8
{ 0xF8, 0x01 } -> 替换为 0xFB
{ 0xF8, 0x02 } -> 替换为 0xFD
{ 0xF8, 0x03 } -> 替换为 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

4 回答 4

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);
            }
        }
    }
}  
于 2013-03-15T12:49:33.457 回答
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);
于 2013-03-15T12:53:38.590 回答
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;
}
于 2013-03-15T12:58:34.297 回答
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会发生 an。如果您关心,您将不得不添加一个小检查以查看字节值是否在范围内,并决定如果不是则做什么(不替换字节,删除转义,抛出异常)。

于 2013-03-15T13:20:22.287 回答