tcl string command does not work with regexp backreference

161 Views Asked by At

see code below, as an example, I am trying to find use regsub with backrefeence as means of selectively using string toupper. I am not getting what I have expected.
See simple example below (yes, I know that I can use string toupper $string 0 0, however, this is just for showing the principle, in a simple example).

> puts [ regsub {^(.)} "min" "s\\1" ]
smin
> puts [ regsub {^(.)} "min" [ string toupper "\\1" ] ]
min

As can be seen, string toupper applied on backreference does not work, but the backrefernce can be used in a double quote operation.
I am using TCL ver. 8.6

1

There are 1 best solutions below

2
On BEST ANSWER

The string toupper is working, but not doing what you want; string toupper "\\1" is just the string \1 so the regsub isn't having much effect. The problem is that regsub doesn't have any way of doing “run this command at the substitution sites”; I've been wanting to fix that for years, but have never actually done so (too many projects for this one to make it to the fore).

Instead, you need to regsub in a command substitution into the string and then subst the result, but in order to do that, you need to first make the string otherwise safe to subst with string map. Fortunately, that's actually pretty simple.

I've split this apart to make it easier for you to examine exactly what each stage is doing:

set str "here is an example with \$dollars, \[brackets\] and \\backslashes"

# Quote all of Tcl's metacharacters; there's not that many
set safer [string map {[ \\[ ] \\] \\ \\\\ $ \\$} $str]

# Inject the command we want to run where we want to run it
set withsubst [regsub {^(.)} $safer {[string toupper {\1}]}]

# Perform the substitution
set result [subst $withsubst]