【TCL】【2】字符串操作与文件操作
TCL字符串操作字符串操作字符串运算符format 和 scanregexpresubstringcompareequalmatchindexrangemapfirst last文件操作基本读写操作文件查找(glob)示例1判断文件是否存在获取文件属性(file)字符串操作TCL 把所有的输入都当作字符串看待所以 TCL 提供了较强的字符串操作功能TCL 中与字符串操作有关的命令string、format、regexp、regsub、scan等字符串运算符TCL中有4个用于表达式的字符串操作符e, ne, in, ni。eq和ne用来检查字符串是否相等如果相等eq返回 1ne返回 0如果不等ne返回 1eq返回 0。in和ni用来判断 List 中是否包含某个字符串如果包含in返回 1ni返回 0。, !等操作符都可以进行字符串比较这些操作符仅在至少有一个操作数不能解析为数值时才进行字符串比较。如下所示setx8sety 010expr($x$y);# 结果时 1.TCL把x和y8进制当作数值处理format 和 scanformat命令类似于 C 语言中的print命令用于格式化输出一些内容。语法formatformatstring ?vlue value...?示例1文本对齐其中%-10s表示字符串要占据 10 个字符串的位置对其方式是左对齐如果不使用-默认是右对齐。scan命令的语法如下scan stringformatvarName ?varName...?scan命令可以认为是format命令的逆其功能类似于 C 语言中的scanf函数。它按format提供的格式分析 string 字符串然后把结果存到变量 varName 中,注意除了空格和 TAB 键之外string 和 format 中的字符和’%必须匹配。scan命令的返回值是匹配的变量个数示例% scansome 26 34some %d %da b2%seta26%setb34% scan12.34.56.78%d.%d.%d.%dc d e f4% puts[formatthe value of c is %d,d is %d,e is %d ,f is %d$c$d$e$f]the value of c is12,d is34,e is56,f is78format和scan命令中使用的特殊符号的含义如下符号含义%s普通字符串%d整数%.2f浮点数2是小数点后两位%c字符%o八进制%x十六进制regexpregexp命令用于判断某个正则表达式是否全部或部分匹配某个字符串匹配返回1否则0。基本用法regexp ?switchs? ?--? exp string ?matchVar? ?subMatchVar subMatchVar...?regexp 命令比较字符串 string 是否与正则表达式 exp 部分或者全部匹配并可以将字符串中的子字符串提取出来。如果字符串的某个子字符串和正则表达式匹配则返回 1否则返回 0。如果在 string 变量后面还有其它的变量称之为匹配变量match variables则这些变量就保存了那些与正则表达式匹配的子字符串信息可能是子字符串的实际内容也可能是界定子字符串的起始、结束的索引数字。matchVar 保存了匹配 exp 的字符串而 subMatchVar 则保存正则表达式中的组匹配的字符串。常用选项注意事项在 TCL 语法中使用{}可以让所有特殊字符都将成为普通字符失去其特殊意义。所以在使用regexp命令的时候可以使用{}将 exp 部分括起来这样就可以专注于正则表达的书写而不需要注意使用转义符号。# 双引号写法\d 需要写成 \\d否则 TCL 先处理 \dregexp^\\d\\.\\d$3.14;# 繁琐容易出错# 花括号写法所见即所得regexp{^\d\.\d$}3.14;# 清晰干净但是使用{}的问题就是正则表达中无法使用 TCL 变量。如果需要使用变量就只能使用双引号。setxhello# 双引号TCL 会先展开变量和转义序列regexp$x\dhello123;# 实际传给 regexp 的是: hello\dresubstringstring命令具有强大的操作字符串的功能其中的 option 选项多达 20 个部分常用的选用如下所述。需要注意的是使用string操作字符串的时候默认是区分大小写的。comparestring compare ?-nocase? ?-length int? string1 string2把字符串 string1 和 string2 根据字典顺序进行比较如果字符串相同则返回0如果 str1 的顺序比 str2 靠前就返回 -1对于其它情况返回1。如果有-length参数那么只比较前 int 个字符如果 int 为负数那么这个参数被忽略。如果有-nocase参数那么比较时不区分大小写。equalstring equal ?-nocase? ?-length int? string1 string2把字符串 string1 和 string2 进行比较如果两者相同返回值为 1否则返回 0。其他参数和string compare相同matchstring match ?-nocase? pattern string如果 pattern 匹配 string那么返回 1否则返回 0。如果有-nocase参数,那么就不区分大小写.在 pattern 中可以使用通配符:*匹配 string 中的任意长的任意字符串,包括空字符串.?匹配 string 中任意单个字符[chars]匹配字符集合 chars 中给出的任意字符,其中可以使用 A-Z 这种形式\x匹配单个字符 x,使用\是为了让 x 可以为字符*、-、[、]示例% string match{a[b-f]cdef}abcdef1# 注意一定要用{,否则 TCL 解释器会把 b-f 当作命令名从而导致错误indexstring index${srting}charIndex返回字符串中第 charIndex 个字符(0-based)。charIndex 可以是下面的值整数 n: 字符串中第 n 个字符(0-based)end: 最后一个字符end整数 n倒数第 n 个字符。string index abcd end-1返回字符’c’如果 charIndex 小于 0或者大于字符串 string 的长度那么返回空。rangestring range${srting}first last返回字符串中从第 first 个到第 last 个字符的子字符串(0-based)。如果 first0那么first 被看作 0如果 last 大于或等于字符串的长度那么 last 被看作 end如果 first 比 last大那么返回空。mapstring map 是一个用于字符串替换的命令它可以按照指定的映射关系替换字符串中的字符或子字符串。string map{old1 new1 old2 new2...}string该命令可以将 string 中所有出现的 old1 替换为 new1old2 替换为 new2依此类推。默认情况下区分大小写未匹配到 old则不会发生替换。map命令的替换是严格按顺序执行的并且后续映射不会影响已替换的部分如下所示# Example 1setstrabcsetnew_str[string map{a1b2ab x}$str]puts$new_str;# 输出: 12c先替换 a→1b→2ab 未被匹配# Example 2# 先替换 a 为 b再替换 b 为 csetnew_str[string map{a b b c}aabb]puts$new_str;# 输出: bbcc而非预期中的 cccc高级用法① 动态生成映射列表映射列表可以通过变量或表达式动态生成setreplacements{a1b2c3}setstra-b-csetnew_str[string map$replacements$str]puts$new_str;# 输出: 1-2-3② 删除字符将 new 设为空字符串可实现删除操作setstrHello, 123 World!setnew_str[string map{, }$str]puts$new_str;# 输出: Hello123World!first laststring first和string last用来在主字符串中搜索指定子串的位置如下所示# 定义主字符串setstrhello world hello tcl# 0123456789# 1. string first找第一个 hello 的位置setfirst_idx[string firsthello$str]# 结果0第一个hello从索引0开始# 2. string last找最后一个 hello 的位置setlast_idx[string lasthello$str]# 结果12最后一个hello从索引12开始# 3. 找不到子串返回-1setno_idx[string firsttest$str]# 结果-1可以指定从某个索引之后开始搜索精准定位setstra b c a b c# 0123456789# 从索引3开始找第一个asetfirst[string firsta$str3]# 结果6# 从索引8开始找最后一个bsetlast[string lastb$str8]# 结果4支持空格、符号等任意字符匹配setstrname:alice|age:20# 0123456789# 找第一个冒号位置setfirst_colon[string first:$str]# 4# 找最后一个竖线位置setlast_pipe[string last|$str]# 10一个常用的技巧是结合返回的索引用string range截取子字符串setstruser:tom:12345# 找到第一个冒号截取后面的内容setcolon_idx[string first:$str]setresult[string range$str$colon_idx1 end]# 结果tom:12345文件操作TCL 提供了丰富的文件操作的命令。通过这些命令你可以对文件进行操作以顺序或随机方式读写文件检索系统保留的文件信息如最后访问时间)。基本读写操作TCL 中使用open打开文件其基本用法如下其中access是文件的打开方式。openfile_name ?access?文件的打开方式有如下几种选项作用r只读方式打开文件已经存在默认方式r读写方式打开文件必须已经存在w只写方式打开文件如果文件存在则清空文件内容否则创建一个新的空文件w读写方式打开文件如果文件存在则清空文件内容否则创建一个新的空文件a只写方式打开文件文件必须存在并把指针指向文件结尾追加a只读方式打开并把指针指向文件尾。如果文件不存在创建新的空文件open命令返回一个字符串用于表示打开的文件所以真正的文件打开方式为如下其中 fileID 是文件标识符。setfileID[open filename r]当调用别的命令gets,puts,close对打开的文件进行操作时就可以使用这个文件标识符。TCL 有三个特定的文件标识stdin,stdout,stderr分别对应标准输入、标准输出和错误通道任何时候都可以使用这三个文件标识。TCL 中使用gets或read命令读取文件内容使用puts命令进行写文件操作。默认文件输入输出方式是连续的即每个gets或read命令返回的是上次gets或read访问位置后面的字节每个puts命令写数据是接着上次puts写的位置接着写。使用open命令打开文件并完成相关操作之后通常需要使用close命令关闭文件close${fileID}读文件gets命令逐行读取文件忽略行尾的换行符其基本用法如下gets fileId ?varName?fileId 是使用open命令打开文件时指定的文件标识符。如果命令中有 varName 就把该行赋给它并返回该行的字符数文件尾返回-1如果没有 varName 参数返回文件的下一行作为命令结果如果到了文件尾就返回空字符串setf[open$filenamer]while{[gets$fline]}{if{[regexp$pattern$line]}{puts stdout$line}}close$f写文件使用puts命令进行写文件操作其基本用法如下puts ?-nonewline? ?fileId? stringputs命令把 string 写到 fileId 中如果没有nonewline选型该命令会自动添加换行符即每次写一行。该命令的返回值为一空字符串。puts命令使用 C 的标准 I/O 库的缓冲区方案这就意味着使用puts产生的信息不会立即出现在目标文件中。如果你想使数据立即出现在文件中那你就调用flush命令flush fileId;# 把缓冲区内容写到 fileId 标识的文件中命令返回值为空字符串。文件查找(glob)TCL 中glob命令用来对文件名进行操作例如glob *.c *.h的作用是返回当前目录中所有以.c 或.h 为后缀的文件的名称。基本语法glob命令的基本语法如下glob ?options? pattern ?pattern...?常用选项选项作用-nocomplain当没有匹配项时返回空列表。没有-nocomplain 时如果结果是空的就返回错误-directory dir指定搜索的基准目录-types type过滤文件类型d目录, f普通文件, l链接等-tails返回相对于基准目录的文件名需配合 -directory 使用只有文件名没有路径-path强制将 pattern 视为路径处理包含/的复杂 pattern 时使用--标记选项结束后续参数均为匹配 pattern处理以 - 开头的文件名时使用示例1判断文件是否存在TCL 中有很多命令来判断一个文件是否存在。方法1使用file exists命令if{[file exists$filename]}{puts文件存在}else{puts文件不存在}方法2使用glob命令setfiles[glob-nocomplain$filename]if{[llength$files]0}{puts文件存在}else{puts文件不存在}获取文件属性(file)TCL 中的file命令用于获取文件的属性部分用法如下CommandUsagefile dirname返回文件所在的目录file exists如果文件存在返回 1否则返回 0file extension返回文件的拓展名file jion合并构成 pathNamefile nativename返回原生格式的文件名file rootname返回除去拓展名之外的其他部分file split分割文件的 pathNamefile tail返回文件名示例setfile/home/tcl/test.tcl puts[filedirname$file];# /home/tclputs[filetail$file];# test.tclputs[file extension$file];# .tclputs[file nativename$file];# /home/tcl/test.tclputs[file rootname$file];# /home/tcl/testputs[filesplit$file];# / home tcl test.tclputs[filejoin/ home tcl test.tcl];# /home/tcl/test.tcl