I am trying to use curly-braces to define a string { }
instead of double-quotes " "
, so that I don't have to escape several characters (such as $
, [
, ]
).
However, I am running into some problems when my string needs to contain a single {
within it.
I know that I can achieve this by simply using a double-quoted string and escape the {
, but how would I do it using a "curly-brace string"?
Eg.
I want to puts
the following string 'proc foo { } {' to stdout.
puts "proc foo \{ \} \{"
gives me the desired output: 'proc foo { } {'
However, puts { proc foo \{ \} \{ }
gives me: 'proc foo \{ \} \{' by literally printing the backslashes.
If I skip the backslashes, puts { proc foo { } {
, it complains about a missing brace.
Also, if the desired string has a matching closing-brace within it, it works fine.
puts { proc foo { } { } }
gives me the expected: 'proc foo { } { }'
What is the correct way to escape a single unmatched curly-brace in a "curly-brace string"?
Sorry, the terms of service for braced strings require you to have a matching close brace for every open brace. The only way to have non-matching braces is to quote/escape them with a backslash, but no backslash substitutions will be performed, so the backslash goes into the string along with the lone brace.
That doesn't mean you can't construct the string you want, for instance like this:
set foo { proc foo { } }
# -> proc foo { }
append foo "{ "
# -> proc foo { } {
(BTW, you don't need to backslash the braces in a doublequoted string, " proc foo { } { "
will do fine.)
However, the string you are building seems to imply that you are building a procedure definition within a script, and going about it the wrong way. Instead of assembling the definition like this:
set foo { proc foo { } }
# -> proc foo { }
append foo "{ "
# -> proc foo { } {
append foo { puts foo }
# -> proc foo { } { puts foo
append foo " }"
# -> proc foo { } { puts foo }
You should do this:
set name foo
set args {}
set body {puts foo}
proc $name $args $body
which defines the procedure directly. If you need it as a string, wrap it up like this:
set foo [list proc $name $args $body]
# -> proc foo {} {puts foo}
Yes, I am using list
to construct a string. It's because wrapping proc $name $args $body
in double quotes will lead to loss of the list structure of the command. I create a list, and then use the string representation of that list as a string.
If you do it this way, you're working with the Tcl interpretation rules and taking advantage of them, rather than working against them. That means less work and fewer errors.