tcl v8.5正则表达式将元素绑定到字符串

时间:2014-11-14 19:09:42

标签: regex tcl

问题: 我正在尝试转换

"%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
                         }
                      }
                 ...
     }
 }

但这正是我想要避免的模式!

2 个答案:

答案 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中,没有必要引入正则表达式。

文档:foreachjoinlappendlindexlsortsetstring