Adding an additional backslash to elements of TCL list

968 Views Asked by At

I have a list which looks like:

list1 = {a.b.c.d a.bb.ccd\[0\] a.bb.ccd\[1\] ....}

When I operate on the element of the list one by one using a foreach loop:

`foreach ele $list1 {
puts "$ele
}`

I get the following output:

a.b.c.d a.bb.ccd[0] a.bb.ccd[1]

Observe that, the backslash goes missing(due to the tcl language flow).

In order to preserve the same, I want to add an extra backslash to all the elements of list1 having an existing backslash.

I tried :

regsub -all {\} $list1 {\\} list1 (Also tried the double quotes instead of braces and other possible trials).

Nothing seems to work.

Is there a way to make sure the $ele preserves the backslash characters inside the foreach loop, as I need the elements with the exact same characters for further processing.

P.S. Beginner in using regexp/regsub

2

There are 2 best solutions below

3
On BEST ANSWER

If your input data has backslashes in it like that that you wish to preserve, you need to use a little extra work when converting that data to a Tcl list or Tcl will simply assume that you were using the backslashes as conventional Tcl metacharacters. There's a few ways to do it; here's my personal favourite as it is logically selecting exactly the chars that we want (the non-empty sequences of non-whitespaces):

set input {a.b.c.d a.bb.ccd\[0\] a.bb.ccd\[1\] ....}
set items [regexp -all -inline {\S+} $input]
foreach item $items {
    puts $item
}

As you can see from the output:

a.b.c.d
a.bb.ccd\[0\]
a.bb.ccd\[1\]
....

this keeps the backslashes exactly. (Also, yes, I quite like regular expressions. Especially very simple ones like this.)

1
On

As you have defined list1 it is a string. When list1 is used with the foreach command, then the string is converted to a list. Remember that lists in Tcl are really just specially formatted strings that are parsed when converted from a string to a list. As the list elements are parsed, the backslashes are removed in accordance with normal Tcl parsing rules. There are several ways to build lists that contains characters that are significant to the Tcl parser. The code below shows two examples contrasted to your code:

set list1 {a.b.c.d a.bb.ccd\[0\] a.bb.ccd\[1\]}
puts "list1 as a string"
puts $list1

puts "converting the list1 string to a proper list"
foreach ele $list1 {
    puts $ele
}

set list2 [list a.b.c.d {a.bb.ccd\[0\]} {a.bb.ccd\[1\]}]
puts "list2 build by the list command"
puts $list2

puts "list2, element by element"
foreach ele $list2 {
    puts $ele
}

set list3 {a.b.c.d {a.bb.ccd\[0\]} {a.bb.ccd\[1\]}}
puts "list3 build properly quoting each element"
puts $list3

puts "list3, element by element"
foreach ele $list3 {
    puts $ele
}

Running this yields:

list1 as a string
a.b.c.d a.bb.ccd\[0\] a.bb.ccd\[1\]
converting the list1 string to a proper list
a.b.c.d
a.bb.ccd[0]
a.bb.ccd[1]
list2 build by the list command
a.b.c.d {a.bb.ccd\[0\]} {a.bb.ccd\[1\]}
list2, element by element
a.b.c.d
a.bb.ccd\[0\]
a.bb.ccd\[1\]
list3 build properly quoting each element
a.b.c.d {a.bb.ccd\[0\]} {a.bb.ccd\[1\]}
list3, element by element
a.b.c.d
a.bb.ccd\[0\]
a.bb.ccd\[1\]

Your regsub attempt will work if you replace each backslash by two backslashes, but building the list properly is much clearer.