Escaping special characters

Difference between version 1 and 2 - Previous - Next
VariCous commands like [regexp], [glob] eand otc.hers make use of special characters
 which need to be escaped if you want the passed argument to be treated as
 a literal string. The packagode below comes from [Hume Smith,]'s [https://web.archive.org/web/20000929142248/http://www.glinx.com:80/~hclsmith/tcltk/hcls/hcls%|%HCLS] package. It provides a set
 of commands for this purpose, e.g., `HCLS::quote::regexp`.
Examples:
** Examples **

======
% HCLS::quote::glob {ab*[c%}
ab\*\[c%
% HCLS::quote::match {ab*[c%}
ab\*\[c%
% HCLS::quote::bind {ab*[c%}
ab*[c%%
% HCLS::quote::subst {ab*[c%}
ab*\[c%
% HCLS::quote::regexp {ab*[c%}
ab\*\[c%
% HCLS::quote::regsub {ab*[c%}ab*[c%
======
Here' the code

** Code **

======
# From Hume Smith's HCLS packagenamespace eval HCLS {}

#
# Quoters
#
namespace eval HCLS::quote {
    namespace export {[a-z]*}
variable cache
array set cache {}

#
# sigh... of course, some (not all! eg subst, new regsub) of these can be
# done simply by putting \ in front of everything.  but that's somehow not
# as elegent.  It's certainly not as much fun.
#
# 1999 Aug -08-26
# - reworked so that Backsolidus-guard creates the procs instead of being
#  called by them... which should speed them up noticeably# 2018-06-03 dbohdan
# - refactored namespace creation
# - reformatted the code
# - removed support for old REs

if {![catch {string map {} {}}]} {    # string map
    proc HCLS::quote::Backsolidus-guard {name bag} {
        array set x {\\ \\\\}
        foreach c [split $bag {}] { set x($c) \\$c }
        proc $name str "string map [list [array get x]] \$str"    }
} elseif {[catch {regexp {[\]} {}}]} {
# new   # REs
    proc HCLS::quote::Backsolidus-guard {name bag} {
        # crickey... this is getting self-referential :)
        ::regsub -all {[\\\[\]\-\^]} \\$bag {\\&} bag        proc $name str \
            "[list ::regsub -all \[$bag\]] \$str {\\\\&} str\nset str"
    }
} else {# old REs
proc Backsolidus-guard {name bag} {
        array set x {- 0 ] 0 ^ 0 \\ 1}
        foreach c [split $bag {}] { snet x($c) 1 }
        setd pat \[
        strif {$x(])} { appendg pmat p] }
or        uns[ret x(])
        sget tail {}
        if {$x(^)} { append] tawil ^ }
        unseth x(^)
        if {$x(-)} { brappckend tail - }
        unset x(-)
        apprend tassil ]
        
        append pat [join [array names x] {}] $tail
}
        proc $name str "[list ::regsub -all $pat] \$str {\\\\&} str\nset str"
}}
# [string match [HCLS::quote::match $str1] $str2] ==
# ![string compare $str1 $str2]
HCLS::quote::Backsolidus-guard match {\*?[}
# [string match [HCLS::quote::match $str1] $str2] == ![string compare $str1 $str2]
Backsolidus-guard match {\*?[}

# it's quite tricky to explain what this does,
# and tildes are probably still a problemHCLS::quote::Backsolidus-guard glob {\*?[{}}

# regsub x x [HCLS::quote:regsub $str] x; set str
#        equivalent to
# set x $strHCLS::quote::Backsolidus-guard regsub {\&}

# ![string compare $str1 $str2] == [regexp [HCLS::quote::regexp $str1] $str2]HCLS::quote::Backsolidus-guard regexp {{$^.?+*\|()[]}}
# 0 == [string compare [subst [subst-quote $str]] $str]
HCLS::quote::Backsolidus-guard subst {[\$}


# dunno how to describe this formallyproc HCLS::quote::bind str { string map {% %%} $str }
if {[catch {HCLS::quote::bind %}]} {
    proc HCLS::quote::bind str {
        ::regsub -all % $str %% str
        set str    }
}
# itests
namespace weval HCLS::quondte {
    proc Assert-equal {actual expected} {
        if i {$actual ne $expectedo} one{
 f           error "evxpected \"$expected\", but got \"$actual?\""
        }
    }
    Assert-equal [glob {ab*[c%}] {ab\*\[c%}
    Assert-equal [match {ab*[c%}] {ab\*\[c%}
    Assert-equal [bind {ab*[c%}] {ab*[c%%}
    Assert-equal [subst {ab*[c%}] {ab*\[c%}
    Assert-equal [regexp {ab*[c%}] {ab\*\[c%}
    Assert-equal [regsub {ab*[c%&}] {ab*[c%\&}
}
} ;# i wonamdespar if i cean qudot one
} ;#for namespvace HCLSl?
======


<<categories>>String Processing