一个列表与另一个列表的Tcl部分字符串匹配



我正在尝试使用Tcl查找list1中与list2中的项部分字符串匹配的项。

我在用这个,但是速度很慢。有什么更有效的方法可以做到这一点吗?

set list1 [list abc bcd cde]
set list2 [list ab cd]
set l_matchlist [list]
foreach item1 $list1 {
foreach item2 $list2 {
if {[string match -nocase "*${item2}*" $item1]} {
lappend l_matchlist $item1
break
}
}
}

我的实际清单很长,这需要很长时间。这是最好的方法吗?

除了速度慢之外,如果list2包含具有全局通配符的元素(如"?"(,也会出现问题和"*"。

我希望下面的方法能更快地工作。至少它解决了上面提到的问题:

set list1 [list abc BCD ace cde]
set list2 [list cd ab de]
set l_matchlist [list]
foreach item2 $list2 {
lappend l_matchlist 
{*}[lsearch -all -inline -nocase -regexp $list1 (?q)$item2]
}

-regexp选项与(?q)的组合一开始可能看起来很奇怪。它使用正则表达式匹配,然后告诉正则表达式将模式视为文本字符串。但这样做的效果是执行你想要的部分匹配。

这与您的版本不同,因为它可能会以不同的顺序产生结果,并且如果列表1中的同一项目与列表2中的多个项目匹配,则可能会多次报告该项目。

如果这是不希望的,你可以跟进:

set l_matchlist [lmap item1 $list1 {
if {$item1 ni $l_matchlist} continue
set item1
}]

当然,这将减少之前获得的一些速度增益。

您可以作弊,将其从列表处理任务变成字符串处理任务。后者在Tcl中通常要快得多。

下面,我首先将list1变成一个字符串,其中原始列表元素由ASCII字段分隔符字符"分隔;\x1F";。然后可以通过正则表达式搜索在单个循环中获得结果。正则表达式查找由包含项2:的字段分隔符字符限定的第一个子字符串

# convert list to string:
set string1 x1F[join $list1 x1F]x1F
set l_matchlist [list]
foreach item2 $list2 {
# escape out regexp special chars:
set item2 [regsub -all {W} $item2 {\&}]
# use append to assemble regexp pattern
set item2 [append x {[^x1F]*} $item2 {[^x1F]*}][unset x]
if {[regexp -nocase $item2 $string1 match]} {
lappend l_matchlist $match
}
}

最新更新