Tcl 中控制流的概念错误

conceptual error with control flow in Tcl

我有 collection 东西,有些是空的。

我想组成一个collection非空的东西,用分隔符隔开。

这基本上是我在 C++ 中所做的,但是失败了 $ 符号等的任何和所有组合

我已经解决了,谢谢,我想知道失败的原因和原因。

set q1 "a"
set q2 ""
set q3 "c"
set q4 d
set q5 ""    

set answer ""

set needSeparator 0
foreach { var } { 
    q1 q2 q3 q4 q5 
    } {
    if { $var ne "" } {
        if {$needSeparator} {
            append answer " separator "
        }
        append answer $var
        set needSeparator 1
    }
}

# expecting answer to be "a separator c separator d"
puts $answer

编辑 2021-09-14

来自@Shawn

<         if { $var ne "" } { 
--- 
>         if { [set elem [set $var]] ne "" } { 

<         append answer $var 
--- 
>         append answer $elem 

我的努力完成了工作。

不太确定 set 是如何在那里进行取消引用的 但这是另一天的事。

这是一个最小的例子,所以对于试图用 C++ 编程的人来说,相当时髦的答案太复杂了:-)。 qN 是 可怕,来自不同的地方,但最终的代码示例是 sweet and works translated back into my real problem - 见下文

# build compound SELECT 

set q1 [select $mapText "final_text"] 
set q2 [select $parish "parish"] 
set q3 [select $la "local_authority"] 
set q4 [sqSelect $five00] 
set q5 ""     
if {$nation ne "All"} { 
    set q5 {SELECT pin_id AS id FROM gazetteer WHERE nation = '} 
    append q5 $nation "'\n" 
} 
 
set compound {} 

foreach clause {q1 q2 q3 q4 q5} { 
    if {[set q [set $clause]] ne ""} { 
        lappend compound $q 
    } 
} 

if {[llength compound] == 0} { return ""} 
 
set res "WITH pinIds AS (\n" 
append res [join $compound "INTERSECT\n    "] ")\n" 

感谢您的帮助

您最好使用列表、dict 或数组来存储相关值,而不是一堆不同的变量。但是无论您的数据以何种方式存储,lappend 非空值到列表或以其他方式过滤掉空值和 join 结果:

#!/usr/bin/env tclsh

set data {a "" c d ""}

# Using foreach
set answer {}
foreach elem $data {
    if {$elem ne ""} {
        lappend answer $elem
    }
}
puts [join $answer " separator "]

# Using lmap for a more functional style; note eq instead of of ne
set answer [lmap elem $data { if {$elem eq ""} continue; set elem }]
puts [join $answer " separator "]

# Using a dict
set data [dict create q1 a q2 "" q3 c q4 d q5 ""]
set answer {}
# Dict traversal happens in the same order keys were added
dict for {_ elem} $data {
    if {$elem ne ""} {
        lappend answer $elem
    }
}
puts [join $answer " separator "]

当遍历变量名称列表时,您必须使用 set 来获取当前名称的值(在您的代码中,$varq1q2, 等总是不等于空字符串):

set answer {}
foreach varname {q1 q2 q3 q4 q5} {
    set elem [set $varname]
    if {$elem ne ""} {
        lappend answer $elem
    }
}
puts [join $answer " separator "]

不是答案,而是对

上的 array for 评论的回应

array for

的 Tcl 实现
proc array_for {vars arrayName body} {
    if {[llength $vars] != 2} {
        error {array for: "vars" must be a 2 element list}
    }
    lassign $vars keyVar valueVar

    # Using the complicated `upvar 1 $arrayName $arrayName` so that any
    # error messages propagate up with the user's array name
    upvar 1 $arrayName $arrayName \
            $keyVar    key \
            $valueVar  value

    set sid [array startsearch $arrayName]
    # If the array is modified while a search is ongoing, the searchID will
    # be invalidated: wrap the commands that use $sid in a try block.
    try {
        while {[array anymore $arrayName $sid]} {
            set key [array nextelement $arrayName $sid]
            set value [set "${arrayName}($key)"]
            uplevel 1 $body
        }
    } trap {TCL LOOKUP ARRAYSEARCH} {"" e} {
        puts stderr [list $e]
        dict set e -errorinfo "detected attempt to add/delete array keys while iterating"
        return -options $e
    } finally {
        array donesearch $arrayName $sid
    }
    return
}

并添加到 array 集合中:

set map [namespace ensemble configure array -map]
dict set map for ::array_for
namespace ensemble configure array -map $map

鉴于此,可以轻松创建 array values 子命令(与 array names 配对)

proc array_values {arrayName} {
    upvar 1 $arrayName ary
    set values [list]
    array for {name value} ary {lappend values $value}
    return $values
}