3. string first string1 string2 ?startindex?
在string2中从头查找与string1匹配的字符序列,如果找到,那么就返回匹配的第一个字母所在的位置(0-based)。如果没有找到,那么返回-1。如果给出了startindex变量,那么将从startindex处开始查找。例如:
% string first ab defabc
3
% string first ab defabc 4
-1
4. string index string charIndex
返回string中第charIndex个字符(0-based)。charIndex可以是下面的值:
整数n: 字符串中第n个字符(0-based)
end : 最后一个字符
end-整数n:倒数第n个字符。string index "abcd" end-1 返回字符'c'
如果charIndex小于0,或者大于字符串string的长度,那么返回空。
例如:
% string index abcdef 2
c
% string index abcdef end-2
d
5. string last string1 string2 ?startindex?
参照3,唯一的区别是从后往前查找
6. string length string
返回字符串string的长度.
7. string match ?-nocase? pattern string
如果pattern匹配string,那么返回1,否则返回0.如果有-nocase参数,那么就不区分大小写.
在pattern 中可以使用通配符:
* 匹配string中的任意长的任意字符串,包括空字符串.
? 匹配string中任意单个字符
[chars] 匹配字符集合chars中给出的任意字符,其中可以使用 A-Z这种形式
\x 匹配单个字符x,使用'\'是为了让x可以为字符*,-,[,].
例子:
% string match * abcdef
1
% string match a* abcdef
1
string match a?cdef abcdef
1
% string match {a[b-f]cdef} abcdef //注意一定要用'{',否则TCL解释器会把b-f当作命令名
1 //从而导致错误
% string match {a[b-f]cdef} accdef
1
8. string range string first last
返回字符串string中从第first个到第last个字符的子字符串(0-based)。如果first<0,那么first被看作0,如果last大于或等于字符串的长度,那么last被看作end,如果first比last大,那么返回空。
10. string replace string first last ?newstring?
返回值为:从字符串string中删除了第first到第last个字符(0-based)的字符串,如果给出了newstring变量,那么就用newstring替换从第first到第last个字符。如果first<0,那么first被看作0,如果last大于或等于字符串的长度,那么last被看作end,如果first比last大或者大于字符串string的长度或者last小于0,那么原封不动的返回string。
13. string trim string ?chars?
返回值为:从string字符串的首尾删除掉了字符集合chars中的字符后的字符串。如果没有给出chars,那么将删除掉spaces、tabs、newlines、carriage returns这些字符。例如:
% string trim "abcde" {a d e}
bc
% string trim " def
> "
def
局部变量和全局变量
对于在过程中定义的变量,因为它们只能在过程中被访问,并且当过程退出时会被自动删除,所以称为局部变量;在所有过程之外定义的变量我们称之为全局变量。TCL中,局部变量和全局变量可以同名,两者的作用域的交集为空:局部变量的作用域是它所在的过程的内部;全局变量的作用域则不包括所有过程的内部。这一点和C语言有很大的不同。如果我们想在过程内部引用一个全局变量的值,可以使用global命令。
% set a 4
4
% proc sample { x } {
global a
incr a
return [expr $a+$x]
}
% sample 3
8
%set a
5
全局变量a在过程中被访问,在过程中对a的改变会直接反映到全局上。如果去掉语句global a,TCL会出错,因为它不认识变量a。
另外,TCL的过程定义还支持可变个数的参数,如果过程的最后一个参数是args,那么就表示这个过程支持可变个数的参数调用。调用时,位于args以前的参数象普通参数一样处理,但任何附加的参数都需要在过程体中作特殊处理,过程的局部变量args将会被设置为一个列表,其元素就是所有附加的变量。如果没有附加的变量,args就设置成一个空串,下面是一个例子:
% proc add { val1 args } {
set sum $val1
foreach i $args {
incr sum $i
}
return $sum
}
则:
add 2 //值为2
add 2 3 4 5 6 //值为20
upvar命令
命令语法: upvar ?level? otherVar myVar ?otherVar myVar ...?
upvar命令使得用户可以在过程中对全局变量或其他过程中的局部变量进行访问,返回值为一个空字符串。upvar命令的第一个参数otherVar是我们希望以引用方式访问的参数的名字,第二个参数myVar是这个过程中的局部变量的名字,一旦使用了upvar命令把otherVar和myVar绑定,那么在过程中对局部变量myVar的读写就相当于对这个过程的调用者中otherVar所代表的局部变量的读写。下面是一个例子:
% proc temp { arg } {
upvar $arg b
set b [expr $b+2]
}
% proc myexp { var } {
set a 4
temp a
return [expr $var+$a]
}
则:
% myexp 7
13
这个例子中,upvar把$arg(实际上是过程myexp中的变量a)和过程temp中的变量b绑定,对b的读写就相当于对a的读写。
upvar命令语法中的level参数表示:调用upvar命令的过程相对于我们希望引用的变量myVar在调用栈中相对位置。例如:
upvar 2 other x
这个命令使得当前过程的调用者的调用者中的变量other,可以在当前过程中利用x访问。缺省情况下,level的值为1,即当前过程(上例中的temp)的调用者(上例中的myexp)中的变量(上例中myexp的a)可以在当前过程中利用局部变量(上例中temp的b)访问。
如果要访问全局变量可以这样写:upvar #0 other x
那么,不管当前过程处于调用栈中的什么位置,都可以在当前过程中利用x访问全局变量other。作者: ameg3 时间: 2009-12-9 17:26 标题: fd 问题10: 如何将一个十进制数转换为十六进制表示
Format命令
% set a 16
16
% set a [format "%#x" $a]
0x10
【Format样例】
#1 案例1
% set labels [format "%-20s %+10s " "Item" "Cost"]
Item Cost
% set price1 [format "%-20s %10d Cents Each" "Tomatoes" "30"]
Tomatoes 30 Cents Each
% set price4 [format "%-20s %10.2f per Lb." "Steak" "3.59997"]
Steak 3.60 per Lb.
#2 案例2
% set a 9
9
% set a [format "%04d" $a]
0009
% set a [format "%+4d" $a]
+9
% set a [format "%-+4d" $a]
+9
% set a [format "%#x" $a]
0x9
% set a [format "%#X" $a]
0X9
% set a 9.9999
9.9999
% set a [format "%4.3f" $a]
10.000
% set a [format "%+6.4f" $a]
+9.9990
% set a [format "%6.4e" $a]
9.9990e+00
% set a [format "%6.4f%%" $a]
9.9990%
% set a 9999999.4321
9999999.4321
% set a [format "%g" $a]
1e+07
% set a [format "%c" 97]
a
#3 案例3
% set a 99999
99999
% set a [format "%04d" $a]
99999
#4 案例4
% set a "alpha"
alpha
% set b a
a
% puts "format with no subst [format {$%s} $b]"
format with no subst $a
% puts "format with subst: [subst [format {$%s} $b]]"
format with subst: alpha
% eval "puts \"eval after format: [format {$%s} $b]\""
eval after format: alpha
#5 案例5
% set a arrayname
% set b index
% set c newvalue
% eval [format "set %s(%s) %s" $a $b $c]
% puts "Index: $b of $a was set to: $arrayname(index)"
Index: index of arrayname was set to: newvalue
#6 案例6
% set cmd "NOT OK"
% eval [format {%s "%s"} puts "Even This Works"]
Even This Works
% set cmd "And even this can be made to work"
% eval [format {%s "%s"} puts $cmd ]
And even this can be made to work
% set cmd {puts "This is Cool!}
% if {[info complete $cmd]} {
eval $cmd
} else {
puts "INCOMPLETE COMMAND: $cmd"
}
INCOMPLETE COMMAND: puts "This is Cool!
#7 案例7
% set num 0
% set cmd "proc temp {} "
% set cmd [format "%s {global num; incr num;" $cmd]
% set cmd [format {%s return "/tmp/TMP.%s.$num"} $cmd 45678]
% set cmd [format "%s }" $cmd ]
% eval $cmd
% puts "[info body temp]"
global num; incr num; return "/tmp/TMP.45678.$num" after#1 after#0
% after 1000 temp
after#0
% after 4000 temp
after#1
% after 8000 temp
after#2
% after info after#0
temp timer
% after info after#1
temp timer
% after info after#2
temp timer
% after info
after#2 after#1 after#0
% after cancel after#0
% after info after#0
event "after#0" doesn't exist
% after cancel temp
% after info after#2
event "after#2" doesn't exist
% after info after#1
temp timer
% after cancel temp
% after info after#1
event "after#1" doesn't exist
% after idle temp
after#4
% after info
after#4
% after info after#4
temp idle
#3 在进程中的其他应用实例
% proc temp1 {} {
after 1000 temp
puts "test 2 with after."
}
% temp1
test 2 with after.
% temp1
test 2 with after.
% after info
after#1 after#0
方法一:
puts stdout "format string" ;#输出输入格式
get stdin var ;#表示从控制台读入字符串
scan $var "format string" varlist ;#表示对字符串进行分析
如果不一次输入,可以用几个这样的组合完成输入过程。
方法二:
你可以先用list生成提示串outputstring
同时生成另一个列表变量存放输入值inputstring
然后用
foreach var $outputstring {
puts $var
get stdin inputstring($var) ;#获取输入
}作者: ameg3 时间: 2009-12-9 17:31 标题: re 问题14:在开发TCL扩展命令时:如何保存TCL扩展命令的多次执行结果?
问题描述:
摘自《研发IT支撑体系》
扩展命令openchIP的功能是打开某IP地址的一个端口:
执行如下命令后:
set pco_id1 [openchIP 10.11.25.634:1762]
set pco_id2 [openchIP 10.11.25.634:1762]
set pco_id3 [openchIP 10.11.25.634:1762]
你的TCL脚本就可以这样写了
set pco_id1 [openchIP 10.11.25.634:1762 var1]
puts $var1
set pco_id2 [openchIP 10.11.25.634:1762 var2]
puts $var2
set pco_id3 [openchIP 10.11.25.634:1762 var3]
puts $var3
你可以任意使用var1-3中的内容作者: ameg3 时间: 2009-12-9 17:32 标题: re 问题14:在开发TCL扩展命令时:如何保存TCL扩展命令的多次执行结果?
问题描述:
摘自《研发IT支撑体系》
扩展命令openchIP的功能是打开某IP地址的一个端口:
执行如下命令后:
set pco_id1 [openchIP 10.11.25.634:1762]
set pco_id2 [openchIP 10.11.25.634:1762]
set pco_id3 [openchIP 10.11.25.634:1762]
1. trace variable name ops command
这个命令设置对变量name的一个跟踪:每次当对变量name作ops操作时,就会执行command命令。name可以是一个简单变量,也可以是一个数组的元素或者整个数组。
ops可以是以下几种操作的一个或几个的组合:
r 当变量被读时激活command命令;
w 当变量被写时激活command命令;
u 当变量被删除时激活command命令,通过用unset命令可以显式的删除一个变量,一个过程调用结束则会隐式的删除所有局部变量。当删除解释器时也会删除变量,不过这时跟踪已经不起作用了。
当对一个变量的跟踪被触发时,TCL解释器会自动把三个参数添加到命令command的参数列表中。这样command实际上变成了 command name1 name2 op
其中op指明对变量作的什么操作。name1和name2用于指明被操作的变量: 如果变量是一个标量,那么name1给出了变量的名字,而name2是一个空字符串;如果变量是一个数组的一个元素,那么name1给出数组的名字,而name2给出元素的名字;如果变量是整个数组,那么name1给出数组的名字而name2是一个空字符串。为了让你很好的理解上面的叙述,下面举一个例子:
% trace variable color w pvar
% trace variable a(length) w pvar
% proc pvar {name element op} {
if {$element !=""} {
set name ${name}($element)
}
upvar $name x
puts "Variable $name set to $x"
}
上面的例子中,对标量变量color和数组元素a(length)的写操作都会激活跟踪操作pvar。我们看到过程pvar有三个参数,这三个参数TCL解释器会在跟踪操作被触发时自动传递给pvar。比如如果我们对color的值作了改变,那么激活的就是pvar color "" w。我们敲入:
% set color green
Variable color set to green
green
command将在和触发跟踪操作的代码同样的上下文中执行:如果对被跟踪变量的访问是在一个过程中,那么command就可以访问这个过程的局部变量。比如:
% proc Hello { } {
set a 2
trace variable b w { puts $a ;list }
set b 3
}
% Hello
2
3
对于被跟踪变量的读写操作,command是在变量被读之后,而返回变量的值之前被执行的。因此,我们可以在command对变量的值进行改变,把新值作为读写的返回值。而且因为在执行command时,跟踪机制会临时失效,所以在command中对变量进行读写不会导致command被递归激活。例如:
% trace variable b r tmp
% proc tmp {var1 var2 var3 } {
upvar $var1 t
incr t 1
}
% set b 2
2
% puts $b
3
% puts $b
4
如果对读写操作的跟踪失败,即command失败,那么被跟踪的读写操作也会失败,并且返回和command同样的失败信息。利用这个机制可以实现只读变量。下面这个例子实现了一个值只能为正整数的变量:
% trace variable size w forceInt
% proc forceInt {name element op} {
upvar $name x
if ![regexp {^[0-9]*$} $x] {
error "value must b a postive integer"
}
}
如果一个变量有多个跟踪信息,那么各个跟踪被触发的先后原则是:最近添加的跟踪最先被触发,如果有一个跟踪发生错误,后面的跟踪就不会被触发。
2. trace vdelete name ops command
删除对变量name的ops操作的跟踪。返回值为一个空字符串。
3. trace vinfo name
这个命令返回对变量的跟踪信息。返回值是一个list,list的每个元素是一个子串,每个子串包括两个元素:跟踪的操作和与操作关联的命令。如果变量name不存在或没有跟踪信息,返回一个空字符串。作者: ameg3 时间: 2009-12-9 17:35 标题: re 问题16:在TCL中如何获取程序执行效率的数据?
if(Tcl_GetIntFromObj(interp, objv[1], &size) != TCL_OK)
{
Tcl_SetResult(interp, "memory size must be number" ,TCL_STATIC);
return TCL_ERROR;
}
p = (_UC*)MAlloc(size);
sprintf(buf, "%d", (_UI)p);
Tcl_SetResult(interp,buf,TCL_VOLATILE);
return TCL_OK;
}作者: ameg3 时间: 2009-12-9 17:39 标题: re 问题20:在TCL中如何实现如下功能:在一个字符串中,得出含有某个单词的个数
问题回答:
没有标准的TCL命令完成此功能,必须自己扩展,可参考如下代码:
# Process name: temp
# Parameters : arg1 ----- the string be searched in arg2
# arg2 ----- the string in which you search arg1
proc temp {arg1 arg2} {
set temp1 [string length $arg1]
set temp2 0
set temp3 [string first $arg1 $arg2 0]
if {$temp3 == -1} {
puts "There is no matched $arg1 in $arg2"
return -1
}
while {$temp3 >= 0} {
incr temp2
set temp3 [string first $arg1 $arg2 [expr $temp3 + $temp1]]
}
puts "Find $arg1 $temp2 times in $arg2..."
return $temp2
}
string命令
问题21:在TCL脚本中如何产生随机数
方法一:编写proc
摘自《研发IT支撑体系》
% set a 4
% proc srand {seed} {
global a
set a $seed
}
% proc rand {} {
global a
set a [expr 1664525 * $a + 1013904223]
}
% srand [clock clicks -milliseconds]
% rand
info exists varName
如果名为varName的变量在当前上下文(作为全局或局部变量)存在,返回1,否则返回0。
info globals ?pattern?
如果没有pattern参数,那么返回包含所有全局变量名字的一个list。如果有pattern参数,就只返回那些和pattern匹配的全局变量(匹配的方式和string match相同)。
info locals ?pattern?
如果没有pattern参数,那么返回包含所有局部变量(包括当前过程的参数)名字的一个list,global和upvar命令定义的变量将不返回。如果有pattern参数,就只返回那些和pattern匹配的局部变量。
info vars ?pattern?
如果没有pattern参数,那么返回包括局部变量和可见的全局变量的名字的一个list。如果有pattern参数,就只返回和模式pattern匹配的局部变量和可见全局变量。模式中可以用namespace来限定范围,如:foo:ption*,就只返回namespace中和option*匹配的局部和全局变量。(注:tcl80以后引入了namespace概念,不过我们一般编写较小的TCL程序,可以对namespace不予理睬,用兴趣的话可以查找相关资料。)
下面针对上述命令举例,假设存在全局变量global1和global2,并且有下列的过程存在:
proc test {arg1 arg2} {
global global1
set local1 1
set local2 2
...
}
然后在过程中执行下列命令:
% info vars
global1 arg1 arg2 local2 local1 //global2不可见
% info globals
global2 global1
% info locals
arg1 arg2 local2 local1
% info vars *al*
global1 local2 local1
2. 查看过程信息
info procs ?pattern?
如果没有pattern参数,命令返回当前namespace中定义的所有过程的名字。如果有pattern参数,就只返回那些和pattern匹配的过程的名字。
info body procname
返回过程procname的过程体,procname必须是一个TCL过程。
info args procname
返回包含过程procname的所有参数的名字的一个list, procname必须是一个TCL过程。
info default procname arg varname
procname必须是一个TCL过程,arg必须是这个过程的一个变量。如果arg没有缺省值,命令返回0;否则返回1,并且把arg的缺省值赋给变量varname。
info level ?number?
如果没有number参数,这个命令返回当前过程在调用栈的位置。如果有number参数,那么返回的是包含在调用栈的位置为number的过程的过程名及其参数的一个list。
下面针对上述命令举例:
proc maybeprint {a b {c 24}} {
if {$a<$b} {
puts stdout "c is $c"
}
}
% info body maybeprint
if {$a<$b} {
puts stdout "c is $c"
}
% info args maybeprint
a b c
% info default maybeprint a x
0
% info default maybeprint c a
1
3. 查看命令信息
info commands ?pattern?
如果没有参数pattern,这个命令返回包含当前namspace中所有固有、扩展命令以及以proc命令定义的过程在内的所有命令的名字的一个list。pattern参数的含义和info procs一样。
info cmdcount
返回了一个十进制字符串,表明多少个命令曾在解释器中执行过。
info complete command
如果命令是command完整的,那么返回1,否则返回0。这里判断命令是否完整仅判断引号,括号和花括号是否配套。
info script
当前有脚本文件正在Tcl解释器中执行,则返回最内层处于激活状态的脚本文件名;否则将返回一个空的字符串。
4. 查看TCL的版本和库
info tclversion
返回为Tcl解释器返回的版本号,形式为major.minor,例如8.3。
info libraray
返回Tcl库目录的完全路径。这个目录用于保存Tcl所使用的标准脚本,TCL在初始化时会执行这个目录下的脚本。作者: ameg3 时间: 2009-12-9 17:42 标题: re 问题24:什么是namespace
【概念】
名字作用域(namespace)是变量和命令的集合,作用域内的变量和命令不受其他作用域的变量或命令影响。Tcl也有这样的一个域,我们通常所指的是全局作用域。全局作用域包含所有的变量和命令,并提供命令让你创建新的作用域。
namespace eval namespacename arg ?arg ...?
如: namespace eval Counter {
variable num 0
proc bump {} {
variable num
incr num
}
}
上面这段脚本创建了一个新的作用域Counter,包括变量num和程序bump,在同一个程序中,作用域内的变量和命令和其它的命令和变量是分开的。如在全局作用域有一命令bump,它与作用域Counter的bump不同。
作用域是动态的,在任何时候可增加或删除。因此,可利用一系列作用域命令建立一个作用域目录,效果与上面显示的namespace定义相同:
namespace eval Counter {
proc test {args} {
return $args
}
}
namespace eval Counter {
rename test ""
}
注意,这测试程序test被加入Counter作用域,而后,由重命名命令rename删了。
作用域可嵌套。
% load tclodbc83
% database
Usage:
database [connect] id datasourcename userid password //数据库连接方法一
database [connect] id connectionstring //数据库连接方法二
database configure operation driver attributelist
database datasources
database drivers
database version
//连接数据库:database [connect] id datasourcename userid password
% database db tcl tcl tcl
db
//访问数据库:id "sql语句"
% set data [db "select * from table1"] //获取表table1中所有字段的内容
{1 a 88} {2 b 100}
% set data [db "select name from table1"] //获取表table1中name字段的内容
a b
其中表table1中有三个字段:ID, name, score,只有两条记录{1 a 88} {2 b 100}
第四步:
对数据库访问到的内容进行操作:
% set data [db "select * from table1 where .."]
{1 a 88} {2 b 100}
变量data实际上保存的就是一个结果集,在TCL中称为list,上面这个list中又嵌套了list
通过循环可以将list中的项一一取出,比如下面的脚本可取出{1 a 88}和{2 b 100},如果需要再精确到某一具体字段,可再嵌套一个循环
set length [llength $data]
for {set i 0} {$i<=$length} {incr i 1} {
set value($i) [lindex $data $i]
puts values($i)
....
}作者: ameg3 时间: 2009-12-9 17:47 标题: re 问题29:如何在TCL中捕获错误
问题回答:
使用catch命令
catch命令:
错误通常导致所有活动的TCL命令被终止,但是有些情况下,在错误发生后继续执行脚本是有用的。例如,你用unset取消变量x的定义,但执行unset时,x可能不存在。如果你用unset取消不存在的变量,会产生一个错误:
% unset x
can't unset "x": no such variable
此时,你可以用catch命令忽略这个错误:
% catch {unset x}
1
catch的参数是TCL脚本。如果脚本正常完成,catch返回0。如果脚本中发生错误,catch会俘获错误(这样保证catch本身不被终止掉)然后返回1表示发生了错误。上面的例子忽略unset的任何错误,这样如果x存在则被取消,即使x以前不存在也对脚本没有任何影响。
catch命令可以有第二个参数。如果提供这个参数,它应该是一个变量名,catch把脚本的返回值或者是出错信息存入这个变量。
%catch {unset x} msg
1
%set msg
can't unset "x": no such variable
在这种情况下,unset命令产生错误,所以msg被设置成包含了出错信息。如果变量x存在,那么unset会成功返回,这样catch的返回值为0,msg存放unset命令的返回值,这里是个空串。如果在命令正常返回时,你想访问脚本的返回值,这种形式很有用;如果你想在出错时利用错误信息做些什么,如产生log文件,这种形式也很有用
问题30:为什么使用puts命令后没有将数据写入文件中?
问题描述:
set filehandle [open testfile.txt a+] //open命令返回一个字符串fileId 用于表识打开的文件
set info "This is test info..."
puts $filehandle $info
......
close #filehandle
TCL提供两个命令来管理当前工作目录:pwd和Cd。
pwd和UNIX下的pwd命令完全一样, 没有参数,返回当前目录的完整路径。
cd 命令也和UNIX命令也一样,使用一个参数,可以把工作目录改变为参数提供的目录。如果cd 没使用参数,UNIX下,会把工作目录变为启动TCL脚本的用户的工作目录,WINDOWS下会把工作目录变为windows操作系统的安装目录所在的盘的根目录(如:C:/)。值得注意的是,提供给cd的参数中路径中的应该用'/'而不是'\',如 cd C:/TCL/lib,这是UNIX的风格。
【样例】
proc temp1 {} {
global conn
set conn 1
puts "setting conn 1"
}
after 1000 temp1
after info
set conn 0
puts "test vwait command and setting conn 0"
puts "waiting for set conn again..."
vwait conn
after info
puts "conn == $conn"
puts "game over"
【输出】
after#0
test vwait command and setting conn 0
waiting for set conn again...
setting conn 1
conn == 1
game over
【解析】
[1] 该命令仅在仿真版本上可行,实际单板操作时不建议使用之;
[2] 注意在执行vwait前后after info的内容,在执行前是存在的,在执行完毕后自动删除id,这与语法描述是相符的作者: ameg3 时间: 2009-12-9 17:54 标题: re re