Tcl中regexp的匹配速度问题

风行水上 @ 2013-08-29 10:44:29
标签:

    一个文件 ~104 MB 大小,查找匹配特定行并提取内容。

    用Tcl代码大致描述如下:

    # EBox: M4-M4 [1234,5678..8765,43321] (name,name) Less than minimum edge length
    
    set RE  {^EBox: (\S+) \[([\d\.\-,]+)\] \(.*?\) (.+)}
    puts [regexp -about $RE]  ;# 据说可以预编译正则表达式
    set fp [open $file r]
    while {[gets $fp line]>=0} {
        if {[regexp $RE $line match layer bbox drc_type]} {
          foreach {llx lly - urx ury} [split $bbox ".,"] break
          lappend bbox_list [list $llx $lly $urx $ury]
        }
    }
    close $fp
    

    上面这部分代码运行时间大致为50秒左右。

    已经验证if语句执行块影响可以忽略,主要瓶颈在regexp语句。

    改动regexp行为 [regexp $RE $line],运行速度可以提高到10秒左右。

    两者的差别仅在于是否提取匹配的子串。对性能影响之大是以前不曾意识到得。原因未明。TODO

    最终改动如下,速度同样可以提高到10秒左右。

    while {[gets $fp line]>=0} {
        if {[regexp $RE $line]} {
          set layer    [lindex $line 1] ; set bbox     [lindex $line 2]
          set drc_type [lrange $line 4 end]
    
          foreach {- llx lly - urx ury} [split $bbox {.,[]}] break
          lappend bbox_list [list $llx $lly $urx $ury]
        }
    }
    

    string match 和 string equal

    set pattern "EBox:*"
    if {[string match $pattern $line]} {
      ... ...
    }
    # 或者 #
    set pattern "EBox:"
    if {[string equal -length [string length $pattern] $pattern $line]} {
      ...
    }
    

    如果把regexp改为string match,运行时间减少到4.6秒左右。

    如果regexp改为string equal,运行时间则为5.1秒左右。

    awk

    好奇着用awk试了一下

    /^EBox:/ {
      layer = $2;
      bbox  = $3;
      drc_type = substr($0, index($0,")")+2);
      #print bbox, layer, drc_type;
      n++;
      bbox_list[n] = bbox;
    }
    

    运行时间在8秒左右。

    awka: 编译成C文件

    把上面的awk程序编译成C程序,同样的文件parsing需要的时间是1秒左右。

    小结

    通过一些不同的方法,程序运行时间可以从50秒缩短到1秒左右。1秒当然还可以更快,但这个探索的过程已经触碰到好几处值得思考和研究的地方。

    TODO

    标签:

      分享到:
      comments powered by Disqus

      29/32ms