Parsing 解码字节流
我有一系列由独立结构定义的消息。这些结构共享在应用程序之间发送的公共头。我正在创建一个解码器,它将获取使用这些结构构建的消息中的原始数据捕获,并将它们解码/解析为一些纯文本 我有1000多条不同的消息需要解码,因此我不确定是否应该用XML定义所有结构格式,然后使用XSL或一些翻译,或者是否有更好的方法来实现这一点 有时我需要解码包含超过一百万条消息的日志,因此性能是一个问题 关于创建解码器/解析器的技术/工具/算法有什么建议吗Parsing 解码字节流,parsing,decoder,Parsing,Decoder,我有一系列由独立结构定义的消息。这些结构共享在应用程序之间发送的公共头。我正在创建一个解码器,它将获取使用这些结构构建的消息中的原始数据捕获,并将它们解码/解析为一些纯文本 我有1000多条不同的消息需要解码,因此我不确定是否应该用XML定义所有结构格式,然后使用XSL或一些翻译,或者是否有更好的方法来实现这一点 有时我需要解码包含超过一百万条消息的日志,因此性能是一个问题 关于创建解码器/解析器的技术/工具/算法有什么建议吗 struct: struct { dword messageid
struct:
struct {
dword messageid;
dword datavalue1;
dword datavalue2;
} struct1;
原始数据示例:
0101010A0A0A0A0F0F0F0F
解码消息(所需输出):
我用C++做这个开发。
关于“性能”——如果你使用磁盘IO和可能的显示IO,我怀疑你的解析器/解码器将不会有什么效果,除非你使用一个真正可怕的算法。 我也不确定问题出在哪里-现在的问题是-一个结构中有3个DWORD,并且您声称基于这些值有1000多条唯一消息 您解码的消息并没有向我暗示您需要任何类型的解析-直接输出似乎可以工作(从字节转换为十六进制值的ascii表示) 如果您确实有一个从值到字符串的映射,那么大开关语句很简单——或者,如果您希望能够动态添加这些语句或更改显示,那么我将在配置文件(文本、xml等)中提供键/值对(映射),然后在读取日志文件/原始数据时进行查找 在这种情况下,我会使用地图如果您提供了值和解码输出的另一个具体示例,我可能会提出一个更合适的建议。如果您已经在示例中使用的语法中给出了消息定义,您绝对不应该尝试手动将其转换为其他语法(XML或其他) 相反,您应该尝试编写一个接受这些方法定义的编译器,并将它们编译成一个解码器函数
现在,建议使用ANTLR作为解析器生成器,使用任何一种ANTLR语言作为实际编译器(Java、Python、Ruby、C#、C++)。然后,编译器应该输出C代码,完成整个解码和漂亮的打印。您可以使用yacc或antlr,添加适当的解析规则,在解析时从中填充一些数据结构(可能是树),然后遍历数据结构并执行任何您喜欢的操作。我假设您所需要做的就是格式化记录并输出它们 使用自定义代码生成器。生成的代码如下所示:
typedef struct { word messageid; } Header;
//repeated for each record type
typedef struct {
word messageid;
// <members here>
} Record_##;
//END
void Process(Input inp, Output out) {
char buffer[BIG_ENOUGH];
char *offset;
offset = &buffer[BIG_ENOUGH];
while(notEnd) {
if(&offset[sizeof(LargestStruct)] >= &buffer[BIG_ENOUGH])
// move remaining buffer to start and fill tail from inp
Header *hpt = (Header*)offset;
switch(hpt->messageid)
{
//repeated for each record type
case <recond ID for given type>:
{
Record_##* rpt = (Record_##*)offset;
outp.format("name1: %t, ...\n", rpt->name1, ...);
offset += sizeof(Record_##);
break;
}
//END
}
}
}
typedef结构{word messageid;}头;
//对每种记录类型重复
类型定义结构{
单词messageid;
//
}记录;
//结束
无效处理(输入输入,输出){
字符缓冲区[足够大];
字符*偏移量;
偏移量=&缓冲区[足够大];
while(notEnd){
if(&offset[sizeof(LargestStruct)]>=&buffer[BIG_-ough])
//将剩余缓冲区移动到起始位置,并从inp填充尾部
页眉*hpt=(页眉*)偏移量;
开关(hpt->messageid)
{
//对每种记录类型重复
案例:
{
记录###*rpt=(记录###*)偏移量;
输出格式(“名称1:%t,…\n”,rpt->name1,…);
偏移量+=sizeof(记录);
打破
}
//结束
}
}
}
大部分是锅炉板,所以编写一个程序来生成它应该不难
如果你需要更多的处理,我认为这个想法可以调整一些,使之工作以及
编辑:重读问题后,您可能已经定义了结构。在这种情况下,您可以将它们包括在内并直接使用。然而,接下来的问题是如何解析结构以生成格式化函数的输入。Awk或sed可能很方便
typedef struct { word messageid; } Header;
//repeated for each record type
typedef struct {
word messageid;
// <members here>
} Record_##;
//END
void Process(Input inp, Output out) {
char buffer[BIG_ENOUGH];
char *offset;
offset = &buffer[BIG_ENOUGH];
while(notEnd) {
if(&offset[sizeof(LargestStruct)] >= &buffer[BIG_ENOUGH])
// move remaining buffer to start and fill tail from inp
Header *hpt = (Header*)offset;
switch(hpt->messageid)
{
//repeated for each record type
case <recond ID for given type>:
{
Record_##* rpt = (Record_##*)offset;
outp.format("name1: %t, ...\n", rpt->name1, ...);
offset += sizeof(Record_##);
break;
}
//END
}
}
}