C# 字节而不是字符上的.NET正则表达式
我正在尝试使用正则表达式进行一些更容易的解析 输入是字节数组(或枚举) 我不想将字节转换为字符,原因如下:C# 字节而不是字符上的.NET正则表达式,c#,.net,regex,boost,byte,C#,.net,Regex,Boost,Byte,我正在尝试使用正则表达式进行一些更容易的解析 输入是字节数组(或枚举) 我不想将字节转换为字符,原因如下: 计算效率 内存消耗效率 某些不可打印的字节转换为字符可能比较复杂。并非所有字节都是可打印的 所以我不能用 P>我知道的唯一解决方案是使用(它在字节-C字符上工作),但是这是一个C++库,用C++ +CLI封装将需要相当大的工作量。 如何直接在.NET中的字节上使用正则表达式,而不使用.NET字符串和字符 谢谢。好吧,如果我遇到这个问题,我会使用C++/CLI包装器,除非我会为我想要实现的
谢谢。好吧,如果我遇到这个问题,我会使用C++/CLI包装器,除非我会为我想要实现的目标创建专门的代码。随着时间的推移,最终开发包装器以完成一般性的工作,但这只是一个选项 第一步是仅包装Boost::Regex输入和输出。在C++中创建专门的函数,它可以完成所有想要的东西,并使用CLI将输入数据传递给C++代码,然后用CLI返回结果。在我看来,这并不是太多的工作要做 更新: 让我试着澄清我的观点。尽管我可能错了,但我相信您无法找到任何可以使用的.NET二进制正则表达式实现。这就是为什么—不管您喜欢与否—您将被迫在CLI包装和字节到字符转换之间进行选择,以使用.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