在tcl中针对规则列表进行有效的字符串搜索

时间:2017-12-20 09:35:44

标签: tcl

我正在尝试验证字符串是否与规则列表匹配。 例如,这些列表项中的哪一个与哪个匹配规则匹配:

set ListToCheck [list abc_123 def_123 ghi_456 abc_345 xyz_987]

set RulesToCheck [list *_123 abc_*]

我最终将列出许多规则的长列表,以检查一长串字符串,并不断增长。我只想要第一场比赛。

我提出的方法似乎有点蛮力。我在想应该有一个更优雅的方法

set match 0
set matchedrule {}
set matchdict {}
foreach value $ListToCheck {
    foreach rule $RulesToCheck {
        if {[string match $rule $value] == 1} {
            set match 1
            set matchedrule $rule
            break
        }
    }
    <take some action on the $value and $rule matched here>
    ...
}

这是最好的方法吗?我觉得应该有更好的方法。

2 个答案:

答案 0 :(得分:0)

如果您的规则是由glob模式真实描述的,那么您可以做很多事情来优化检测哪一个匹配。好吧,除非你得到所有匹配理论并做巧妙的重写,但这很难,但这很难。

可以做一些事情来制作稍微快一点的匹配器。 警告!以下内容包括代码生成。

# Build a lambda that uses [switch -glob]
set ruleset {}
foreach rule $RulesToCheck {
    lappend ruleset $rule [list return [list 1 $rule]]
}
set matcher [list value "switch -glob -- \$value [list $ruleset];return {0 {}}"]

# Now we can use the lambda term as much as we want
foreach value $ListToCheck {
    lassign [apply $matcher $value] match matchedrule
    # take some action on the $value and $rule matched here
    # ...
    # I tested with:
    #    if {$match} {puts "$value was matched by $matchedrule"}
}

我没有计时这段代码,但是要检查合理数量的规则和项目,它应该做得更好,因为它会产生更好的字节码(需要花费apply来做每个匹配,这与调用过程一样昂贵。

答案 1 :(得分:0)

另一种方法是将glob模式的集合转换为单个RE。

# Note that this is Tcl 8.6 syntax - both [lmap] and [string cat] are used
# Rewriting into 8.5 syntax is left as an exercise
set RE [string cat "(" [join [lmap s $RulesToCheck {
    # Assuming you've not got any [...] bits in your glob pattern...
    string cat "^" [string map {* .* ? . \\ {\\}} $s] "$"
}] ")|("] ")"]

foreach value $ListToCheck {
    set matchinfo [regexp -inline -indices -- $RE $value]
    if {[llength $matchinfo]} {
        foreach pattern $RulesToCheck idxs [lrange $matchinfo 1 end] {
            if {[lindex $idxs 0] >= 0} {
                puts "matched $pattern against $value"
                break
            }
        }
    }
}

我不确定在什么情况下这会比我之前建立一个lambda的答案更有效率;确定哪个匹配发生的成本似乎本身就很烦人(虽然如果匹配率足够低且模式足够复杂,那么可能 ......)