TCL regsub uses RegEx match as index in associate array

811 Views Asked by At

I'd like to automatically convert URLs, i.e

I've tried following code snippet in TCL

set loc "https://sc-uat.ct.example.com/sc/"

set envs(dev) "test"
set envs(uat) "beta"
set envs(qa) "demo"

puts $envs(uat)
regsub -nocase {://.+-(.+).ct.example.com} $loc {://inv[$envs(\1)].example.com} hostname

puts "new location = $hostname"

But the result is: new location = https://inv[$envs(uat)].example.com/sc/

It seems that [$envs(uat)] is NOT evaluated and substituted further with the real value. Any hints will be appreciated. Thanks in advance

1

There are 1 best solutions below

0
On

But the result is: new location = https://inv[$envs(uat)].example.com/sc/ It seems that [$envs(uat)] is eval-ed further.

You meant to say: [$envs(uat)] is not evaluated further?

This is because due to the curly braces in {://inv[$envs(\1)].example.com}, the drop-in string is taken literally, and not subjected to variable or command substitution. Besides, you don't want command and variable substitution ([$envs(\1)]), just one of them: $envs(\1) or [set envs(\1)].

To overcome this, you must treat the regsub-processed string further via subst:

set hostname [subst -nocommands -nobackslashes [regsub -nocase {://.+-(.+).ct.example.com} $loc {://inv$envs(\1).example.com}]]

Suggestions for improvement

I advise to avoid the use of subst in this context, because even when restricted, you might run into conflicts with characters special to Tcl in your hostnames (e.g., brackets in the IPv6 authority parts). Either you have to sanitize the loc string before, or, better work on string ranges like so:

if {[regexp -indices {://(.+-(.+)).ct.example.com} $loc _ replaceRange keyRange]} {
    set key [string range $loc {*}$keyRange]
    set sub [string cat "inv" $envs($key)]
    set hostname [string replace $loc {*}$replaceRange $sub]
}