一个列表与另一个列表的 Tcl 部分字符串匹配
Tcl partial string match of one list against another
我正在尝试使用 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 包含具有 glob 通配符(例如“?”)的元素,也会出现问题。和'*'。
我希望下面的方法工作得更快。至少它解决了上面提到的问题:
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)
结合使用乍一看可能很奇怪。它使用正则表达式匹配,然后告诉正则表达式将模式视为文字字符串。但这具有执行您之后的部分匹配的效果。
这与您的版本不同,因为它可能会以不同的顺序生成结果,并且如果 list1 中的同一项目与 list2 中的多个项目匹配,则可能会报告多次。
如果不需要,您可以跟进:
set l_matchlist [lmap item1 $list1 {
if {$item1 ni $l_matchlist} continue
set item1
}]
当然,这会降低之前取得的一些速度收益。
你可以稍微作弊,把它从一个 list-processing 任务变成一个字符串处理任务。后者在 Tcl 中通常要快得多。
下面我先把list1转成一个字符串,原来的列表元素之间用ASCII字段分隔符“\x1F”隔开。然后可以通过正则表达式搜索在单个循环中获得结果。正则表达式查找由包含 item2:
的字段分隔符字符限定的第一个子字符串
# 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
}
}
我正在尝试使用 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 包含具有 glob 通配符(例如“?”)的元素,也会出现问题。和'*'。
我希望下面的方法工作得更快。至少它解决了上面提到的问题:
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)
结合使用乍一看可能很奇怪。它使用正则表达式匹配,然后告诉正则表达式将模式视为文字字符串。但这具有执行您之后的部分匹配的效果。
这与您的版本不同,因为它可能会以不同的顺序生成结果,并且如果 list1 中的同一项目与 list2 中的多个项目匹配,则可能会报告多次。
如果不需要,您可以跟进:
set l_matchlist [lmap item1 $list1 {
if {$item1 ni $l_matchlist} continue
set item1
}]
当然,这会降低之前取得的一些速度收益。
你可以稍微作弊,把它从一个 list-processing 任务变成一个字符串处理任务。后者在 Tcl 中通常要快得多。
下面我先把list1转成一个字符串,原来的列表元素之间用ASCII字段分隔符“\x1F”隔开。然后可以通过正则表达式搜索在单个循环中获得结果。正则表达式查找由包含 item2:
的字段分隔符字符限定的第一个子字符串# 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
}
}