tcl数据格式混乱

时间:2016-11-17 13:56:26

标签: foreach split tcl

这个问题背后的动机是学习......

我已经完成了一些TCL编程,但我确实有一个正常工作的代码,但我不明白为什么有些语法有效,而另一种语法没有。

问题描述: 我正在编写一个需要设置电源和接地网电压的代码。 在我输入VDD网络后,

set POWER_NETS "vdd=1.1 vdda=1.2 vref=1.1"

然后一个简单的TCL代码应该构造并执行以下命令:

set_vdd vdd 1.1
set_vdd vdda 1.2
set_vdd vref 1.1

就是这样。这似乎微不足道,但我在执行它时遇到了一些困难。我仍然不明白为什么有时我的代码不起作用,虽然这对我来说似乎是正确的。

工作解决方案:我提出的唯一可行的解​​决方案是:

foreach ITEM [split $POWER_NETS] {
    set NET [lindex [split $ITEM =] 0]
    set VOLTAGE [lindex [split $ITEM =] 1]
    set_vdd $NET $VOLTAGE
}

这么简单的操作有很多代码。当以更精简的形式书写时,它仍然有效:

foreach ITEM [split $POWER_NETS] {
    set_vdd [lindex [split $ITEM =] 0] [lindex [split $ITEM =] 1]
}

但我仍然觉得这里有改进的余地。

学习目标:我想以此解决方案作为最佳代码解决(它既简短又全面)

foreach ITEM [split $POWER_NETS] {
    set_vdd [split $ITEM =]
}

不幸的是,这不起作用。解释set_vdd命令的工具会抱怨

no value given for parameter "voltage" (use -help for full usage) :

我不明白为什么这不起作用。有什么区别?

当我用set_vdd替换puts时,它会打印所有值。所有信息都在那里。不是吗?

nlv12345@acc3081 CHAR_OUT_LOGS $ tclsh
% set POWER_NETS "vdd=1.1 vdda=1.2 vref=1.1"
vdd=1.1 vdda=1.2 vref=1.1
% foreach ITEM [split $POWER_NETS] {
    puts [split $ITEM =]
}
vdd 1.1
vdda 1.2
vref 1.1
% 

2 个答案:

答案 0 :(得分:4)

错误消息不是最佳的,但问题是您将split中的两个单词作为单个参数传递给set_vdd

如果您的Tcl解释器是任何当前支持的版本,您可以改为执行此操作:

foreach ITEM [split $POWER_NETS] {
    set_vdd {*}[split $ITEM =]
}

{*}是一个标记,表示“取这个列表 - 这个词的其余部分 - 并将其拆分为单独的参数”。虽然它正式不是运营商而是Tcl语言的语法部分,但称其为“扩展运算符”并不会让您感到困惑。

较旧的,不受支持的Tcl版本(8.4及之前版本)需要使用eval来执行此操作。你可能还可以:

foreach ITEM [split $POWER_NETS] {
    eval set_vdd [split $ITEM =]
}

但实际上这样做会更安全:

foreach ITEM [split $POWER_NETS] {
    eval [linsert [split $ITEM =] 0 set_vdd]
}

如您所见,{*}简化了一些事情。

但是,我实际上是这样做的:

foreach {ITEM KEY VALUE} [regexp -all -inline {(\w+)=([\d.]+)} $POWER_NETS] {
    set_vdd $KEY $VALUE
}

就像那样,POWER_NETS价值中出人意料的事情不会造成太大麻烦。 OTOH,如果你不习惯正则表达式,那么现在可能不是时候开始regexp ......

答案 1 :(得分:2)

另外两个简单的解决方案,用于启发和进一步学习:

set POWER_NETS "vdd=1.1 vdda=1.2 vref=1.1"
foreach ITEM [split $POWER_NETS] {
    lassign [split $ITEM =] NET VOLTAGE
    set_vdd $NET $VOLTAGE
}

这个使用lassign分配ITEM的部分,而不是将它们拆分为无名参数。

set POWER_NETS [string map {= { }} "vdd=1.1 vdda=1.2 vref=1.1"]
foreach {NET VOLTAGE} [split $POWER_NETS] {
    set_vdd $NET $VOLTAGE
}

这个用空格替换等号,然后让foreach成对地提取两个值。

文档: foreachlassignsetsplitstring