C# 字节而不是字符上的.NET正则表达式

C# 字节而不是字符上的.NET正则表达式,c#,.net,regex,boost,byte,C#,.net,Regex,Boost,Byte,我正在尝试使用正则表达式进行一些更容易的解析 输入是字节数组(或枚举) 我不想将字节转换为字符,原因如下: 计算效率 内存消耗效率 某些不可打印的字节转换为字符可能比较复杂。并非所有字节都是可打印的 所以我不能用 P>我知道的唯一解决方案是使用(它在字节-C字符上工作),但是这是一个C++库,用C++ +CLI封装将需要相当大的工作量。 如何直接在.NET中的字节上使用正则表达式,而不使用.NET字符串和字符 谢谢。好吧,如果我遇到这个问题,我会使用C++/CLI包装器,除非我会为我想要实现的

我正在尝试使用正则表达式进行一些更容易的解析

输入是字节数组(或枚举)

我不想将字节转换为字符,原因如下:

  • 计算效率
  • 内存消耗效率
  • 某些不可打印的字节转换为字符可能比较复杂。并非所有字节都是可打印的
  • 所以我不能用

    <> P>我知道的唯一解决方案是使用(它在字节-C字符上工作),但是这是一个C++库,用C++ +CLI封装将需要相当大的工作量。 如何直接在.NET中的字节上使用正则表达式,而不使用.NET字符串和字符


    谢谢。

    好吧,如果我遇到这个问题,我会使用C++/CLI包装器,除非我会为我想要实现的目标创建专门的代码。随着时间的推移,最终开发包装器以完成一般性的工作,但这只是一个选项

    第一步是仅包装Boost::Regex输入和输出。在C++中创建专门的函数,它可以完成所有想要的东西,并使用CLI将输入数据传递给C++代码,然后用CLI返回结果。在我看来,这并不是太多的工作要做

    更新:

    让我试着澄清我的观点。尽管我可能错了,但我相信您无法找到任何可以使用的.NET二进制正则表达式实现。这就是为什么—不管您喜欢与否—您将被迫在CLI包装和字节到字符转换之间进行选择,以使用.NET的正则表达式。在我看来,包装器是更好的选择,因为它会工作得更快。我没有做任何基准测试,这只是基于以下假设:

  • 使用包装器,您只需强制转换 指针类型(字节和字符)
  • 使用.NET的正则表达式,您必须 转换输入的每个字节

  • 这里有一点阻抗失配。您希望使用.Net中使用字符串(多字节字符)的正则表达式,但希望使用单字节字符。不能像往常一样同时使用.Net和.Net

    然而,为了打破这种不匹配,您可以以面向字节的方式处理字符串并对其进行变异。变异后的字符串可以充当可重用的缓冲区。这样,您就不必将字节转换为字符,或将输入缓冲区转换为字符串(根据您的问题)

    例如:

    //BLING
    byte[] inputBuffer = { 66, 76, 73, 78, 71 };
    
    string stringBuffer = new string('\0', 1000);
    
    Regex regex = new Regex("ING", RegexOptions.Compiled);
    
    unsafe
    {
        fixed (char* charArray = stringBuffer)
        {
            byte* buffer = (byte*)(charArray);
    
            //Hard-coded example of string mutation, in practice you would
            //loop over your input buffers and regex\match so that the string
            //buffer is re-used.
    
            buffer[0] = inputBuffer[0];
            buffer[2] = inputBuffer[1];
            buffer[4] = inputBuffer[2];
            buffer[6] = inputBuffer[3];
            buffer[8] = inputBuffer[4];
    
            Console.WriteLine("Mutated string:'{0}'.",
                 stringBuffer.Substring(0, inputBuffer.Length));
    
            Match match = regex.Match(stringBuffer, 0, inputBuffer.Length);
    
            Console.WriteLine("Position:{0} Length:{1}.", match.Index, match.Length);
        }
    }
    
    使用这种技术,您可以分配一个字符串“buffer”,它可以重新用作Regex的输入,但每次都可以使用字节对其进行变异。这避免了每次要进行匹配时将字节数组转换\编码为新的.Net字符串的开销。这可能被证明是非常重要的,因为我在.Net中看到许多算法试图以每小时100万英里的速度运行,结果却因为字符串生成、随后的堆垃圾和GC花费的时间而崩溃

    显然这是不安全的代码,但它是.Net

    不过,正则表达式的结果将生成字符串,因此这里有一个问题。我不确定是否有一种使用Regex的方法不会生成新字符串。您当然可以获得匹配索引和长度信息,但字符串生成违反了您对内存效率的要求

    更新


    实际上,在反汇编Regex\Match\Group\Capture之后,它似乎只在您访问Value属性时生成捕获的字符串,因此如果您只访问index和length属性,则至少可能不会生成字符串。但是,您将生成所有支持ReGeX对象。

    < P>作为使用不安全的替代方案,只需考虑编写一个简单的递归比较器,例如:

    static bool Evaluate(byte[] data, byte[] sequence, int dataIndex=0, int sequenceIndex=0)
    {
           if (sequence[sequenceIndex] == data[dataIndex])
           {
               if (sequenceIndex == sequence.Length - 1)
                   return true;
               else if (dataIndex == data.Length - 1)
                   return false;
               else
                   return Evaluate(data, sequence, dataIndex + 1, sequenceIndex + 1);
           }
           else
           {
               if (dataIndex < data.Length - 1)
                   return Evaluate(data, sequence, dataIndex+1, 0);
               else
                   return false;
           }
    }
    
    静态布尔求值(字节[]数据,字节[]序列,int-dataIndex=0,int-sequenceIndex=0)
    {
    if(序列[sequenceIndex]==数据[dataIndex])
    {
    if(sequenceIndex==sequence.Length-1)
    返回true;
    else if(dataIndex==data.Length-1)
    返回false;
    其他的
    返回评估(数据、序列、数据索引+1、序列索引+1);
    }
    其他的
    {
    if(数据索引<数据长度-1)
    返回评估(数据、序列、数据索引+1,0);
    其他的
    返回false;
    }
    }
    

    您可以通过多种方式提高效率(即寻找第一个字节匹配,而不是迭代等),但这可以让您开始。。。希望能有所帮助。

    我个人采用了不同的方法,编写了一个可以扩展的小型状态机。我相信,如果解析协议数据,这比正则表达式可读性好得多

    bool ParseUDSResponse(PassThruMsg rxMsg, UDScmd.Mode txMode, byte txSubFunction, out UDScmd.Response functionResponse, out byte[] payload)
    {
        payload = new byte[0];
        functionResponse = UDScmd.Response.UNKNOWN;
        bool positiveReponse = false;
        var rxMsgBytes = rxMsg.GetBytes();
    
        //Iterate the reply bytes to find the echod ECU index, response code, function response and payload data if there is any
        //If we could use some kind of HEX regex this would be a bit neater
        //Iterate until we get past any and all null padding
        int stateMachine = 0;
        for (int i = 0; i < rxMsgBytes.Length; i++)
        {
            switch (stateMachine)
            {
                case 0:
                    if (rxMsgBytes[i] == 0x07) stateMachine = 1;
                    break;
                case 1:
                    if (rxMsgBytes[i] == 0xE8) stateMachine = 2;
                    else return false;
                case 2:
                    if (rxMsgBytes[i] == (byte)txMode + (byte)OBDcmd.Reponse.SUCCESS)
                    {
                        //Positive response to the requested mode
                        positiveReponse = true;
                    }
                    else if(rxMsgBytes[i] != (byte)OBDcmd.Reponse.NEGATIVE_RESPONSE)
                    {
                        //This is an invalid response, give up now
                        return false;
                    }
                    stateMachine = 3;
                    break;
                case 3:
                    functionResponse = (UDScmd.Response)rxMsgBytes[i];
                    if (positiveReponse && rxMsgBytes[i] == txSubFunction)
                    {
                        //We have a positive response and a positive subfunction code (subfunction is reflected)
                        int payloadLength = rxMsgBytes.Length - i;
                        if(payloadLength > 0)
                        {
                            payload = new byte[payloadLength];
                            Array.Copy(rxMsgBytes, i, payload, 0, payloadLength);
                        }
                        return true;
                    } else
                    {
                        //We had a positive response but a negative subfunction error
                        //we return the function error code so it can be relayed
                        return false;
                    }
                default:
                    return false;
            }
        }
        return false;
    }
    
    bool ParseUDSResponse(PassThruMsg rxMsg,UDScmd.Mode txMode,byte txSubFunction,out UDScmd.Response functionResponse,out byte[]有效载荷)
    {
    有效载荷=新字节[0];
    functionResponse=UDScmd.Response.UNKNOWN;
    bool positiveResponse=假;
    var rxMsgBytes=rxMsg.GetBytes();
    //迭代应答字节以查找echod ECU索引、响应代码、功能响应和有效负载数据(如果有)
    //如果我们可以使用某种十六进制正则表达式,这会更整洁一些
    //迭代直到我们通过任何和所有空填充
    int stateMachine=0;
    for(int i=0;i