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

时间:2010-06-12 13:09:52

标签: c# .net regex boost byte

我正在尝试使用正则表达式进行一些解析。

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

由于以下原因,我不想将字节转换为字符:

  1. 计算效率
  2. 内存消耗效率
  3. 某些不可打印的字节可能很复杂,无法转换为字符。并非所有字节都是可打印的。
  4. 所以我不能使用Regex

    我所知道的唯一解决方案是使用Boost.Regex(适用于字节 - C字符),但这是一个C ++库,使用C ++ / CLI进行包装将需要相当多的工作。

    如何直接在.NET中的字节上使用正则表达式,而无需使用.NET字符串和字符?

    谢谢。

4 个答案:

答案 0 :(得分:8)

此处存在一些阻抗不匹配。您希望使用.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中的许多算法试图以每小时一百万英里的速度通过字符串生成以及随后的堆垃圾邮件和在GC中花费的时间来降低。

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

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

<强>更新

实际上在反汇编Regex \ Match \ Group \ Capture后,看起来它只在访问Value属性时生成捕获的字符串,因此如果只访问索引和长度属性,则至少不能生成字符串。但是,您将生成所有支持的Regex对象。

答案 1 :(得分:2)

好吧,如果我遇到这个问题,我会做C ++ / CLI包装器,除了我为我想要实现的目标创建专门的代码。最终用时间开发包装器做一般事情,但这只是一个选项。

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

<强>更新

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

  1. 使用包装器,你只需要施放 指针类型(字节&lt; - &gt;字符)。
  2. 使用.NET的正则表达式     转换输入的每个字节。

答案 2 :(得分:1)

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

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

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

答案 3 :(得分:0)

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

<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />