【问题标题】:Efficient parsing using pyparsing使用 pyparsing 进行高效解析
【发布时间】:2015-05-29 15:42:13
【问题描述】:

我是 pyparsing 模块的新手,我正在尝试从超过 60000 行的文件中解析下面显示的示例字符串。我需要从每一行中提取数据。然而,目前的实施似乎太慢了。我的代码中是否有一些多余的东西可以优化? 到目前为止,对于具有多处理功能的 23MB 文件,我大约需要 2 分钟,而我的主要性能瓶颈是解析例程。

Example strings : 
Mar 16 14:12:25.989 [ABC] [ID=0][core#16] [65536][3131927075092] random: message
    or 
Mar 23 13:57:07.888 [123] [core#2 ] [00][3851708823] random message 2

Grammar:

nums::          '0'...'9'
num::           (nums+)
words::         'a'..'z' 'A'...'Z'
word::          (words+)

colon::         ':'
time::          ((num) + colon)+ '.' + (num)
date::          (word) + (num) + (time)

open brace::    "["
close brace::   "]"

is AP::     (open brace) + (word) + (close brace)
is BP::     (open brace) + (num) + (close brace)

oct id::        (open brace) + (word) + ("=") + (num) + (close brace)
core id::       (open brace) + (word) + ("#") + (num) + (close brace)
ppm id::        (open brace) + (num) + (close brace)
oct timestamp:: (open brace) + (num) + (close brace)
hexnum::        (hexnums+)
pcap dump::     (hexnum +(":")) + (hexnum)+
tags::          (date) + (is AP|is BP)? + (oct id)? + (core id) + (ppm id)? + (oct timestamp)? + (pcap dump)?

'''

    self.num = Word(nums)
    self.word = Word(alphas)
    self.open_brace = Suppress(Literal("["))
    self.close_brace = Suppress(Literal("]"))
    self.colon = Literal(":")
    self.stime = Combine(OneOrMore(self.num + self.colon) + self.num + Literal(".") + self.num)
    self.date = OneOrMore(self.word) + self.num + self.stime
    self.is_ap = self.open_brace + self.word + self.close_brace
    self.is_bp = self.open_brace + self.num + self.close_brace
    self.oct_id = self.open_brace + Suppress(self.word) + Suppress(Literal("=")) \
            + self.num + self.close_brace
    self.core_id = self.open_brace + Suppress(self.word) + Suppress(Literal("#")) \
            + self.num + self.close_brace
    self.ppm_id = self.open_brace + self.num + self.close_brace
    self.oct_ts = self.open_brace + self.num + self.close_brace
    self.dump = Suppress(Word(hexnums) + Literal(":")) + OneOrMore(Word(hexnums))
    self.opening = Suppress(self.date) \
            + Optional(self.is_ap.setResultsName("AP")|self.is_bp.setResultsName("BP")) \
            + Optional(self.oct_id.setResultsName("oct").setParseAction(lambda toks:int(toks[0]))) \
            + self.core_id.setResultsName("core").setParseAction(lambda toks:int(toks[0])) \
            + Optional(self.ppm_id.setResultsName("ppm").setParseAction(lambda toks:int(toks[0])) \
            + self.oct_ts.setResultsName("timestamp").setParseAction(lambda toks:int(toks[0]))) \
            + Optional(self.dump.setResultsName("pcap"))

【问题讨论】:

    标签: multiprocessing python-2.6 pyparsing


    【解决方案1】:

    我并没有真正找到很多提高绩效的机会,但可以改进的一个要素是您对时间的定义。

    self.stime = Combine(OneOrMore(self.num + self.colon) + self.num + Literal(".") + self.num)
    

    假设时间总是采用“hh:mm:ss.ccc”的形式,使用 OneOrMore 读取前导“hh:mm:”总是会付出尝试匹配“self.num + self.colon”的代价在退出 OneOrMore 之前反对秒和小数点。您可以用显式重复替换 OneOrMore:

    self.stime = Combine(self.num + self.colon + self.num + self.colon + self.num + Literal(".") + self.num)
    

    或者使用最近添加的乘法运算符:

    self.stime = Combine((self.num + self.colon)*2 + self.num + Literal(".") + self.num)
    

    仅此一项更改就将我的性能测试时间缩短了约 10%。

    但是,我真的建议为此使用正则表达式。可读性并没有太大损失,您可以使用单个 Regex 折叠 Combine、OneOrMore 等中的多个元素匹配:

    self.stime = Regex(r"\d\d:\d\d:\d\d\.\d\d\d")
    

    与您的原始表单相比,更改为 Regex 使我的性能测试时间减少了 25%。

    (没有必要在这方面做得过火——例如,用“Regex(r"\d+")”替换“Word(nums)”并没有真正的好处——事实证明,Word 在内部使用正则表达式。)

    我还重新格式化了您的 self.opening 定义以使用调用语法来定义结果名称 - 我发现这种形式更容易理解:

    self.opening = (Suppress(self.date) 
            + Optional(self.is_ap("AP") | self.is_bp("BP")) 
            + Optional(self.oct_id("oct")  .setParseAction(lambda toks:int(toks[0]))) 
            + self.core_id("core")         .setParseAction(lambda toks:int(toks[0])) 
            + Optional(self.ppm_id("ppm")  .setParseAction(lambda toks:int(toks[0])) 
            + self.oct_ts("timestamp")     .setParseAction(lambda toks:int(toks[0]))) 
    

    没有性能优势,但您不必阅读所有“.setResultsName”垃圾。 (我也不喜欢反斜杠。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-19
      相关资源
      最近更新 更多