问题: 我正在尝试转换
"%0 %1 ... %n"
到
"[lindex $someList 0] [lindex $someList 1] ... [lindex $someList n]"
使用正则表达式
regsub -all "(%\c*)" $string "\[lindex \$someList \0\]" string
它不起作用 - 我得到了,而不是:
"[lindex $someList ]0 [lindex $someList ]1 ... [lindex $someList ]n"
上下文:
基本上我正在尝试编写一个函数,它将对给定的一组列表(或者换言之,它们的笛卡尔积)的所有排列执行某些操作,例如,如果我有以下内容:
set action "puts \"%1 hello %0 world\""
和一组列表
[1 2 3] [a b]
然后调用
foreach_n $action [list 1 2 3] [list a b]
我期待结果
a hello 1 world
b hello 1 world
a hello 2 world
b hello 2 world
a hello 3 world
b hello 3 world
我编写的函数(尚未完全检查边缘情况)是:
proc foreach_n { action args } {
foreach el [lindex $args 0] {
foreach_n_helper $action [list $el] {*}[lrange $args 1 end]
}
}
proc foreach_n_helper { action fixed_elem_values args } {
foreach el [lindex $args 0] {
set fixed_vals [list {*}$fixed_elem_values $el]
if {[llength $args] > 1} {
foreach_n_helper $action $fixed_vals {*}[lrange $args 1 end]
} else {
#I simply cannot get this bit correct
regsub -all "(%\c*)" $action "\[lindex \$fixed_vals \0\]" action
puts "$fixed_vals"
puts $action
#eval $action
}
}
}
并运行
foreach_n $action [list 1 2 3] [list a b]
我看到我想要对每个排列进行评估的语句是:
1 a
puts "[lindex $fixed_vals ]1 hello [lindex $fixed_vals ]0 world"
1 b
puts "[lindex $fixed_vals ]1 hello [lindex $fixed_vals ]0 world"
2 a
puts "[lindex $fixed_vals ]1 hello [lindex $fixed_vals ]0 world"
2 b
puts "[lindex $fixed_vals ]1 hello [lindex $fixed_vals ]0 world"
3 a
puts "[lindex $fixed_vals ]1 hello [lindex $fixed_vals ]0 world"
3 b
puts "[lindex $fixed_vals ]1 hello [lindex $fixed_vals ]0 world"
所以递归就像我想要的那样,但如果我真的试图评估它们,整个事情就会崩溃,因为索引超出了[lindex ...] 根据{{3}}的文档,我尝试支持subSpec“[lindex \ $ fixed_vals \ 0]”,输出结果为
1 a
puts ""\[lindex \$fixed_vals %\]"1 hello "\[lindex \$fixed_vals %\]"0 world"
1 b
puts ""\[lindex \$fixed_vals "\[lindex \$fixed_vals %\]"\]"1 hello "\[lindex \$fixed_vals "\[lindex \$fixed_vals %\]"\]"0 world"
2 a
puts ""\[lindex \$fixed_vals %\]"1 hello "\[lindex \$fixed_vals %\]"0 world"
2 b
puts ""\[lindex \$fixed_vals "\[lindex \$fixed_vals %\]"\]"1 hello "\[lindex \$fixed_vals "\[lindex \$fixed_vals %\]"\]"0 world"
3 a
puts ""\[lindex \$fixed_vals %\]"1 hello "\[lindex \$fixed_vals %\]"0 world"
3 b
puts ""\[lindex \$fixed_vals "\[lindex \$fixed_vals %\]"\]"1 hello "\[lindex \$fixed_vals "\[lindex \$fixed_vals %\]"\]"0 world"
这可能意味着我误解了文件中陈述的内容(或其他......)。我也尝试过“随机”,并且无处可去。
有人可以帮忙吗?如果有更好的方法来实现我的目标,我会很高兴听到它。
注意:我意识到我可以通过采用以下模式来实现我的目标:
foreach el1 $list1 {
foreach el2 $list2 {
.
.
.
... foreach eln $listn {
call some function taking n parameters
}
}
...
}
}
但这正是我想要避免的模式!
答案 0 :(得分:1)
我没有阅读每一个细节。你错过了subst
命令吗?
% set string "%0 %1 ... %3"
%0 %1 ... %3
% set new [regsub -all {%(\d+)} $string {[lindex $someList \1]}]
[lindex $someList 0] [lindex $someList 1] ... [lindex $someList 3]
% set someList {first second third fourth}
first second third fourth
% subst $new
first second ... fourth
答案 1 :(得分:1)
如果您在一个过程中生成一个字符串,然后想要用生成的字符串替换该字符串中的标记,那么正则表达式可能是最不实用的方法。
将字符串"%0 %1 ... %n"
转换为"[lindex $someList 0] [lindex $someList 1] ... [lindex $someList n]"
非常简单,因为可以从输入字符串构造结果字符串:
foreach group "%0 %1 %2 %3" {
lappend res "\[lindex \$somelist [string range $group 1 end]]"
}
join $res
如果您希望输入字符串的内容从数据列表中选择项目,则更简单:
set data [list foo bar baz qux]
set input "%0 %3 %1 %2 %1"
# use lmap in Tcl 8.6
foreach i [lsort -unique $input] d $data {lappend map $i $d}
string map $map $input
# => foo qux bar baz bar
等等。一切都已经存在于Tcl中,没有必要引入正则表达式。