赞
踩
目录
[12] Substitution and word boundaries
everything-is-string
Tcl 脚本是由一条或者多条命令 command 组成的字符串。分号 Semi-colons 和换行符 newlines 用作命令分隔符,除非被引用。命令置换 substitution 期间,右方括号 ] 用作命令终止符,除非被引用。
- # 定义一些变量
- set var1 10
- set var2 20
- # 执行一些算术运算
- set x [expr {$var1 + $var2}];puts "The sum is: $x"
- set y [expr {$var1 - $var2}];puts "The difference is: $y"
- # 定义带有参数的过程并调用它
- proc greet {name} {
- puts "Hello, $name"
- }
- greet "Alice";greet "Bob"
- # 用花括号引用包含空格的命令参数
- set msg {Hello Tcl!}
- puts $msg
- # 使用花括号引用包含换行符的字符串
- set fruits {apple
- banana
- orange
- }
- puts "The fruits are: $fruits"
- # 通过花括号或者反斜线来定义一个包含方括号的变量值
- set var [0] ; # 这样写程序会报错 invalid command name "0"
- set var \[0\] ; puts $var ;# 通过 \ 转义来实现
- set var {[0]} ; puts $var ;# 通过 {} 引用来实现

在 Tcl 中,命令的执行 evaluated 分为两个步骤:首先,Tcl 解释器 interpreter 会将命令拆分成单词 words 并执行置换 substitutions,包括使用花括号来保护单词、执行命令替换和变量替换。接下来,解释器会用第一个单词来查找和定位要执行的命令过程,然后所有的单词会被传递给该命令过程。该命令过程可以以任意方式解释每个单词,如 integer、variable name、list 或 Tcl script。
在 Tcl 中,每个命令过程都有自己的参数解析规则,解释器会根据需要对每个命令过程传递的单词进行解释。内置命令在 Tcl 中的解析规则可以根据其功能和行为来确定。
例如,在以下代码示例中:
set x 10
Tcl 解释器首先将上述命令拆分成 3 个单词,将第一个单词 set 用来定位和查找 set 命令过程,并将其余的单词 x 和 10 分别传递给该过程。set 命令过程将第二个单词 x 解释为一个变量名,并将第三个单词 10 解释为变量 x 的值,并将其设置为 10。因此,在此代码示例中,将变量 x 的值设置为 10。
- # 执行命令替换时解释器会执行嵌套在方括号中的命令,并将输出结果作为替换的字符串。
- # [expr 2+3] 被字符串 5 替换
- # 替换后在按照 set 命令来执行过程
- set x [expr 2+3]
-
- # 执行变量替换时解释器会通过美元符号将变量引用替换为其对应的值
- puts $x ;#输出结果 5
-
- # 花括号保护单词,使其不受Tcl解释器的影响,花括号内部作为字符串字面量而不是变量的值
- puts {$x} ;#输出结果 $x
在 Tcl 中,命令中的单词以空格 white space 分隔(除了换行符 newlines 外,换行符表示命令分隔符 command separators )
在 Tcl 中,如果一个词的第一个字符是双引号 quotes,则该词的末尾将由下一个双引号字符终止。如果在双引号之间出现分号、或空格字符(包括换行符),则它们将被视为普通字符并包含在单词中。在 Tcl 中,双引号中的字符可以进行命令 Command 、变量 variable 和反斜杠 backslash 替换。并且双引号不会作为单词的一部分保留。
- # 错误用法
- puts "This is a "quote" inside a string."
- # 输出结果
- extra characters after close-quote
- while executing
- "puts "This is a "q"
-
- # 正确用法
- puts "This is a \"quote\" inside a string."
- # 输出结果
- This is a "quote" inside a string.
-
- # 双引号之间有空格、方括号、分号、换行符的情况
- puts "; and \[\] and {} and
- newlines"
- # 输出结果
- ; and [] and {} and
-
- newlines

如果一个单词以字符串 {*} 开头,后面跟着一个非空白字符,那么 {*} 将被删除,该单词的其余部分将被解析并替换为任何其他单词。 {*} 语法用于将列表中的值展开为单独的参数。
- proc max {args} {
- set max_value [lindex [lsort -real -decreasing $args] 0]
- puts "The max value is $max_value"
- }
- set my_list {1 2 3 4}
- max {*}$my_list
这段代码的功能是,查找列表中的最大值并输出它。
首先定义了名为 max 的过程,并用 args 关键字接受可变数量的输入参数。并使用 lsort 命令对列表排序,-real 表示按照数值进行排序,-decreasing 表示降序。在使用 lindex 获取排序后的第一个元素,即最大值。并将其存储在变量 max_value 中,最后用 puts 命令输出。
定义了一个名为 my_list 的列表,并通过 {*} 符号来将列表元素打散,作为参数传递给 max 过程。
对于一对花括号 {} 之间的字符,Tcl 做如下处理:如果一个单词的第一个字符是开放括号 { ,那么这个单词的结束符是匹配的闭合括号 } 。花括号内的字符将被保留,而括号本身将被忽略。花括号之间的字符不执行任何替换除了反斜杠+换行符,反斜杠和换行符将被替换为单个空格。
- set x 1
- puts {$x is\ 1}
- # 输出结果
- $x is\ 1
- puts {$x is\
- 1}
- # 输出结果
- $x is 1 ;# 发现反斜线没有,这也是唯一能在花括号内发生的替换
如果一个单词包含左方括号 [ ,那么 TCL 将执行命令替换。为此,它递归调用 TCL 解释器,以处理方括号后面的字符作为 TCL 脚本。脚本可以包含任意数量的命令,并必须以右方括号 ] 结束。脚本的结果(即其最后一个命令的结果)将替换到单词中,并替换掉它们之间的所有字符。在单词中可能有任意数量的命令替换。命令替换不会对用花括号括起来的单词执行。
- # TCL 解释器将递归调用自身6次,每次都会执行一个新的命令替换。
- # 在每次递归调用中,TCL 解释器将方括号内的字符作为新的 TCL 命令进行解释和执行
- # 直到所有的命令替换都被执行完毕。
- puts [expr {1 + [expr {2 + [expr {3 + [expr {4 + [expr 5]}]}]}]}]
-
- # 在这个例子中,最终结果为 15,因为我们计算了 1 + 2 + 3 + 4 + 5 的总和
- # 输出结果
- 15
在 TCL 中,如果一个单词包含美元符号 $ 和以下形式之一,那么 TCL 会执行变量置换:美元符号和其后面的字符将被该变量的值替换。变量置换可以采用以下任意形式:
- set fruit apple
- puts "I like $fruit!";# 不会报错,因为Tcl认为 !为特殊字符,在变量替换时,遇到!自动截止
- puts "I like ${fruit}!" ;# 二者输出结果一样
- # 输出结果
- I like apple!
-
- # 花括号用于确保Tcl正确识别变量边界
- puts "I like ${fruit}s."
- # 输出结果
- I like apples.
-
- # 下面是错误用法
- puts "I like $fruits"
- # 输出结果
- can't read "fruits": no such variable
- while executing
- "puts "I like $fruits" "

反斜线序列 | 替换结果 |
\t | 制表符 |
\n | 换行符 |
\v | 垂直制表符 |
\r | 回车 |
\f | 换页符 |
\b | 删除 |
\\ | 反斜线本身 |
\a | 警告音 |
\<whitespace> | 一个空格符 |
\ooo | 八进制数的 ASCII 码 |
\xhh | hh 是一个两位十六进制数 |
\uhhhh | 其中 hhhh 是一个四位十六进制数 |
\uhhhhhhhh | 其中 hhhhhhhh 代表该字符的 8 位十六进制表示形式的数值 |
- # 制表符
- set str "Name:\tBob\tAge:\t25"
- puts $str
- # 换行符
- set str_1 "Name:\tBob\nAge:\t25"
- puts $str_1
- # 垂直制表符
- set str_2 "Name:\tBob\vAge:\t25"
- puts $str_2
- # 回车符
- set str_3 "Name:\tBob\rAge:\t25"
- puts $str_3
- # 换页符
- set str_4 "Name:\tBob\fAge:\t25"
- puts $str_4
- # 删除符
- set str_5 "Name:\tBob\bAge:\t25"
- puts $str_5
- # 反斜线本身
- set str_6 "A backslash: \\"
- puts $str_6
- # 警告音
- # 当这个语句执行时,计算机会发出一个嗡嗡声。
- # 注意,在不同的系统上,可能会有不同的声音效果,或者根本不会有声音效果。
- # 警告音在实际编程中可能不太常见,但在某些场景下可能有用,例如在需要引起用户注意的情况下。
- puts "Beep! \a"
- # 在TCL中,反斜线加换行可用于将一个长行的代码分成多行,使其更易于阅读和维护。
- # 在代码中,反斜线加换行必须在行末使用。
- set str_7 "This is a very long string\
- that spans multiple lines."
- puts $str_7

上述代码输出结果如下:
在 TCL 中,\ooo 转义序列可以用于表示八进制数的 ASCII 码。其中 ooo 是一个三位八进制数,可以是任意的 0~7 数字组合。例如,\101 表示大写字母 A ,\142 表示小写字母 b 。这个转义序列通常用于在代码中插入 ASCII 字符。例如,在下面的示例中,我们使用 \101 将大写字母 A 插入到字符串中:
set my_string "Hello \101 world!" puts $my_string ;# 输出:Hello A world!在 TCL 中,还可以使用 \xhh 转义序列表示任意的 ASCII 码,其中 hh 是一个两位十六进制数。例如,\x41 等同于 \101,表示大写字母 A 。这个转义序列通常用于在代码中插入二进制数据或特殊字符。
set my_string "Hello \x41 world!" puts $my_string ;# 输出:Hello A world!在 TCL 中,\uhhhh 是一个 Unicode 转义序列,用于在字符串中插入 Unicode 字符,其中hhhh 是一个四位十六进制数,表示要插入的 Unicode 字符的编号。例如,\u0416 表示Unicode 码点 U+0416 ,对应于字符 Ж 。需要注意的是,在 TCL 中不支持所有的 Unicode 字符,因此需要先确定所使用的字符是否由 TCL 支持。如果字符串中包含\u转义序列,TCL会自动将其转换为 Unicode 字符。例如,在下面的示例中,我们使用 \u0416 将 Unicode 字符 Ж 插入到字符串中:
\Uhhhhhhhh 这个貌似终端不兼容,输出来不对!
在 Tcl 中,如果一个井号字符 # 出现在解释器期望一个命令的第一个单词的第一个字符的位置上,则从井号字符开始并一直到下一个换行符出现的位置上的所有字符都将被视为注释并被忽略。注释字符仅在出现在命令的开头时才具有意义。
- # This is valid comment puts "Hello,Tcl!"
- puts "Hello,Tcl!" ;# This is valid comment
- puts "Hello,Tcl!" # This is invalid comment
在创建命令的单词时,Tcl 解释器会对每个字符进行一次处理。例如,如果发生变量替换,则不会对变量的值执行其他替换;变量的值会原样插入到单词中。如果发生命令替换,则嵌套命令会完全由递归调用 Tcl 解释器处理;在进行递归调用之前不会执行其他替换,并且不会对嵌套脚本的结果执行其他替换。置换从左到右执行。
- set y [set x 0][incr x][incr x]
- puts $y
- # 输出结果
- 012
在 Tcl 中,替换操作不会影响命令的单词边界,除了在规则 [5] 中指定的参数扩展中。例如,在变量替换过程中,变量的整个值将成为单个单词的一部分,即使变量的值包含空格也是如此。
- set my_list {abc {ab c} {a b c}}
- foreach element $my_list {
- set length [string length $element]
- puts "The string length of \"$element\" is $length"
- }
- # 输出结果
- The string length of "abc" is 3
- The string length of "ab c" is 4
- The string length of "a b c" is 5
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。