The problem often comes up "I have a string with parentheses, I want to perform (some operation) on it, how do I do it?" A lot of time is spent playing with regexps, which can't really ever work. I decided to try to write a canonical parser for parenthesised expressions. I hope others will suggest better models, and that in the end we will have an implementation worthy of going into tcllib. CMcC 26Jun2012
There's also a Parse Quote equivalent.
# parpar - parse parenthesised strings # # returns a paired list containing parenthesis depth of string and string # example: [parpar "zero(one)((two))"] -> "0 zero 1 one 2 two" proc parpar {str {l (} {r )}} { set depth 0 set result {} set skip 0 foreach c [split $str ""] { if {$c eq "\\"} { append run $c incr skip } elseif {$skip} { append run $c set skip 0 continue } if {$c eq $l} { # OPEN if {[info exists run]} { lappend result $depth $run unset run } incr depth } elseif {$c eq $r} { # CLOSE if {$depth > 0} { if {[info exists run]} { lappend result $depth $run unset run } } else { error "parpar unbalanced '$l$r' in '$str'" } incr depth -1 } else { append run $c } } if {$depth > 0} { error "parpar dangling '$l' in '$str'" } if {[info exists run]} { lappend result $depth $run } return $result } if {[info exists argv0] && $argv0 eq [info script]} { package require tcltest namespace import ::tcltest::* verbose {pass fail error} set count 0 foreach {str result} { () "" (()) "" (moop) "1 moop" ((moop)) "2 moop" "zero(one)((two))" "0 zero 1 one 2 two" "pebbles (fred wilma) bambam (barney betty)" "0 {pebbles } 1 {fred wilma} 0 { bambam } 1 {barney betty}" "zero (one (two (three (four (five)))))" "0 {zero } 1 {one } 2 {two } 3 {three } 4 {four } 5 five" {\(skip\)} "0 \\(skip\\)" } { test parpar-[incr count] {} -body { parpar $str } -result $result } foreach {str} { "(((()" ")))" } { test parpar-[incr count] {} -body { parpar $str } -match glob -result * -returnCodes 1 } }