将 regsub 中的匹配项与 & 传递给过程(正在使用 Tcl)

Passing a match in regsub with & to a procedure (Tcl is being used)

我想遍历逗号分隔的字符串并用更多逗号分隔的元素替换匹配项。

即 regsub 之后的 5-A,B 应该给我 1-A,2-A,3-A,4-A,5-A,B

以下内容对我不起作用,因为 & 作为实际 & 而不是实际匹配项传递:

regsub -all {\d+\-\w+} $string [myConvertProc &]

但是不尝试传递 & 并直接使用它有效:

regsub -all o "Hello World" &&&
> Hellooo Wooorld

不确定我在尝试将值传递给 myConvertProc

时做错了什么

编辑: 我认为我最初的问题是 [myConvertProc &] 首先被评估,所以我实际上是通过 '& ' 到程序。

如何在正则表达式领域解决这个问题?可能吗?

编辑 2: 我已经在拆分列表上使用 foreach 解决了它,所以我只是想看看如果这在 regsub 中是可能的。谢谢!

您在第一次编辑时是正确的:问题是 regsub 的每个参数在执行命令之前都已完全评估。

一种解决方案是在字符串中插入命令替换字符串,然后在其上使用subst

set string [regsub -all {\d+\-\w+} $string {[myConvertProc &]}]
# -> [myConvertProc 5-A],B
set string [subst $string]
# -> 1-A,2-A,3-A,4-A,5-A,B

这只有在 string 中没有其他内容需要替换的情况下才有效(但您当然可以关闭变量和反斜杠替换)。

foreach 解决方案要好得多。另一种 foreach 解决方案是遍历 regexp -indices -inline -all 的结果,但如果可行,最好遍历拆分列表的各个部分。

更新:

典型的 foreach 解决方案如下:

set res {}
foreach elem [split $string ,] {
    if {[regexp -- {^\d+-\w+$} $elem]} {
        lappend res [myConvertProc $elem]
    } else {
        lappend res $elem
    }
}
join $res ,

也就是说,您通过查看原始列表中的每个元素来收集结果列表。如果该元素符合您的要求,则将其转换并将结果添加到结果列表中。如果元素不匹配,您只需将其添加到结果列表即可。

在 Tcl 8.6 中可以稍微简化一下:

join [lmap elem [split $string ,] {
    if {[regexp -- {^\d+-\w+$} $elem]} {
        myConvertProc $elem
    } else {
        set elem
    }
}] ,

这是一回事,但 lmap 命令会为您处理结果列表。

文档:foreach, lappend, lmap, regexp, regsub, set, split, subst