用正则解析FIX协议?
我需要解析一些包含FIX协议消息的日志文件。
每一行都包含一些头部信息(比如时间戳、日志级别、端点),然后是FIX的负载部分。
我用正则表达式把头部信息解析成了命名组。例如:
<?P<datetime>\d{2}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}.\d{6}) (?<process_id>\d{4}/\d{1,2})\s*(?P<logging_level>\w*)\s*(?P<endpoint>\w*)\s*
接下来我就要处理FIX负载本身(^A是每个标签之间的分隔符),例如:
8=FIX.4.2^A9=61^A35=A...^A11=blahblah...
我需要从中提取特定的标签(比如从35=中提取"A",或者从11=中提取"blahblah"),并忽略其他所有内容——基本上,我需要忽略"35=A"之前的所有东西,以及"11=blahblah"之前的所有内容,然后再忽略之后的内容等等。
我知道有一些库可以解析每一个标签(http://source.kentyde.com/fixlib/overview),不过我希望能用正则表达式简单处理一下,因为我其实只需要几个标签。
有没有好的方法用正则表达式提取我需要的标签呢?
谢谢,
Victor
3 个回答
^A 实际上是 \x{01},这就是它在 vim 中的显示方式。在 perl 里,我是通过先用十六进制的 1 来分割,然后再用 "=" 来分割的。在第二次分割时,数组的第一个值 [0] 是标签,第二个值 [1] 是对应的值。
其实不需要先用"\x01"分割,然后再用正则表达式处理,再过滤。假如你只想要标签34、49和56(分别是MsgSeqNum、SenderCompId和TargetCompId),你可以直接用正则表达式:
dict(re.findall("(?:^|\x01)(34|49|56)=(.*?)\x01", raw_msg))
如果你确定发送方的数据中没有会导致简单正则表达式出错的嵌入数据,那么像这样的简单正则表达式就能正常工作。具体来说:
- 没有原始数据字段(其实是数据长度和原始数据的组合,比如RawDataLength和RawData(95/96)或者XmlDataLen和XmlData(212,213))
- 没有用于unicode字符串的编码字段,比如EncodedTextLen和EncodedText(354/355)
处理这些特殊情况需要额外的解析工作。我使用了一个自定义的Python解析器,但即使是你提到的fixlib代码在这些情况下也会出错。不过,如果你的数据没有这些例外情况,上面的正则表达式应该能返回你想要的字段的一个不错的字典。
编辑:我把上面的正则表达式保留原样,但应该修改一下,让最后的匹配元素变成(?=\x01)
。具体的解释可以在@tropleee的回答中找到。
可以使用一些正则表达式工具,比如expresso或者regexbuddy。
你可以先用^A
来分割文本,然后对每一部分使用([^=])+=(.*)
这个规则进行匹配,把结果放进一个哈希表里。你还可以设置一个开关,默认情况下不添加你不感兴趣的标签,同时对你感兴趣的标签可以进行处理。