使用格式命令的参数扩展
Argument expansion with format command
我遇到了一个场景,我需要在 format
命令中使用参数扩展。在 Tcl8.5 中,我使用的是 {*}
,它的效果非常好。
但是,对于 Tcl8.4,我已经尝试过 eval
。但是,没有运气。
% set x "This is Whosebug"
This is Whosebug
% format "%10s %5s %20s" {*}$x
This is Whosebug
% eval format "%10s %5s %20s" $x
%5s
% eval list format "%10s %5s %20s" $x
format %10s %5s %20s This is Whosebug
% eval [list format "%10s %5s %20s" $x]
not enough arguments for all format specifiers
% eval format "%10s %5s %20s" [list $x]
%5s
% eval format "%10s %5s %20s" [concat $x]
%5s
我这里的错误是什么?
请参阅文章的 eval and double substitution 部分。
正确的方法是:
eval "format {%10s %5s %20s} $x"
此处 eval
无法连接任何参数,因此解释器得到的是替换形式:format {%10s %5s %20s} This is Whosebug
。您当然可以使用 eval "format \"%10s %5s %20s\" $x"
但我更喜欢尽可能避免使用反斜杠转义。
eval format "%10s %5s %20s" $x
是错误的,因为 eval 首先将字符串连接在一起,所以你最终得到:
eval format %10s %5s %20s $x
这就像说 format %10s %5s %20s $x
,这就是为什么你得到你所得到的)
eval list format "%10s %5s %20s" $x
变为:
eval list format %10s %5s %20s $x
这就像说 list format %10s %5s %20s $x
并没有让 format
实际做某事。
eval [list format "%10s %5s %20s" $x]
方向正确,但 $x
没有得到扩展,所以你正在做 format "%10s %5s %20s" $x
。
其他人只将 $x
放入更深的列表中,或者在这种情况下不做任何更改。
如果编写诸如eval
之类的concat-and-evaluate命令的调用方式不清楚,通常可以将命令替换为concat
以查看有关内容待评估,例如concat format "%10s %5s %20s" $x
而不是 eval format "%10s %5s %20s" $x
.
这些形式扁平化格式化字符串,使第二个格式说明符成为第一个值参数(前两个是等效的,$x
是一个扁平列表,因此与 [concat $x
] 相同):
concat format "%10s %5s %20s" $x
# -> format %10s %5s %20s This is Whosebug
concat format "%10s %5s %20s" [concat $x]
# -> format %10s %5s %20s This is Whosebug
concat format "%10s %5s %20s" [list $x]
# -> format %10s %5s %20s {This is Whosebug}
此表单还插入了一个不属于此处的列表命令:
concat list format "%10s %5s %20s" $x
# -> list format %10s %5s %20s This is Whosebug
这种形式保留了格式化字符串的列表结构,可惜也保留了$x
:
的列表结构
concat [list format "%10s %5s %20s" $x]
# -> format {%10s %5s %20s} {This is Whosebug}
这两种形式做了正确的事情:它们保留了格式字符串但展平了参数列表:
concat "format {%10s %5s %20s} $x"
# -> format {%10s %5s %20s} This is Whosebug
concat [list format {%10s %5s %20s}] $x
# -> format {%10s %5s %20s} This is Whosebug
8.4 习惯用法是使用 linsert
创建要评估的命令
set x "This is Whosebug"
set args [split $x]
set cmd [linsert $args 0 format "%10s %5s %20s"]
set formatted [eval $cmd]
或者,嵌套在一行中
set formatted [eval [linsert [split $x] 0 format "%10s %5s %20s"]]
我遇到了一个场景,我需要在 format
命令中使用参数扩展。在 Tcl8.5 中,我使用的是 {*}
,它的效果非常好。
但是,对于 Tcl8.4,我已经尝试过 eval
。但是,没有运气。
% set x "This is Whosebug"
This is Whosebug
% format "%10s %5s %20s" {*}$x
This is Whosebug
% eval format "%10s %5s %20s" $x
%5s
% eval list format "%10s %5s %20s" $x
format %10s %5s %20s This is Whosebug
% eval [list format "%10s %5s %20s" $x]
not enough arguments for all format specifiers
% eval format "%10s %5s %20s" [list $x]
%5s
% eval format "%10s %5s %20s" [concat $x]
%5s
我这里的错误是什么?
请参阅文章的 eval and double substitution 部分。
正确的方法是:
eval "format {%10s %5s %20s} $x"
此处 eval
无法连接任何参数,因此解释器得到的是替换形式:format {%10s %5s %20s} This is Whosebug
。您当然可以使用 eval "format \"%10s %5s %20s\" $x"
但我更喜欢尽可能避免使用反斜杠转义。
eval format "%10s %5s %20s" $x
是错误的,因为 eval 首先将字符串连接在一起,所以你最终得到:
eval format %10s %5s %20s $x
这就像说 format %10s %5s %20s $x
,这就是为什么你得到你所得到的)
eval list format "%10s %5s %20s" $x
变为:
eval list format %10s %5s %20s $x
这就像说 list format %10s %5s %20s $x
并没有让 format
实际做某事。
eval [list format "%10s %5s %20s" $x]
方向正确,但 $x
没有得到扩展,所以你正在做 format "%10s %5s %20s" $x
。
其他人只将 $x
放入更深的列表中,或者在这种情况下不做任何更改。
如果编写诸如eval
之类的concat-and-evaluate命令的调用方式不清楚,通常可以将命令替换为concat
以查看有关内容待评估,例如concat format "%10s %5s %20s" $x
而不是 eval format "%10s %5s %20s" $x
.
这些形式扁平化格式化字符串,使第二个格式说明符成为第一个值参数(前两个是等效的,$x
是一个扁平列表,因此与 [concat $x
] 相同):
concat format "%10s %5s %20s" $x
# -> format %10s %5s %20s This is Whosebug
concat format "%10s %5s %20s" [concat $x]
# -> format %10s %5s %20s This is Whosebug
concat format "%10s %5s %20s" [list $x]
# -> format %10s %5s %20s {This is Whosebug}
此表单还插入了一个不属于此处的列表命令:
concat list format "%10s %5s %20s" $x
# -> list format %10s %5s %20s This is Whosebug
这种形式保留了格式化字符串的列表结构,可惜也保留了$x
:
concat [list format "%10s %5s %20s" $x]
# -> format {%10s %5s %20s} {This is Whosebug}
这两种形式做了正确的事情:它们保留了格式字符串但展平了参数列表:
concat "format {%10s %5s %20s} $x"
# -> format {%10s %5s %20s} This is Whosebug
concat [list format {%10s %5s %20s}] $x
# -> format {%10s %5s %20s} This is Whosebug
8.4 习惯用法是使用 linsert
创建要评估的命令
set x "This is Whosebug"
set args [split $x]
set cmd [linsert $args 0 format "%10s %5s %20s"]
set formatted [eval $cmd]
或者,嵌套在一行中
set formatted [eval [linsert [split $x] 0 format "%10s %5s %20s"]]