我对读取文本文件,识别模式并替换该模式值的tcl过程感兴趣。假设“数据”是所需的模式,并且当前值为1 2 3,如何将每个“数据”实例的值更新为值3 2 1?我曾多次尝试使用fileutil
package,但没有设法替换这些值。有什么建议?
您不需要fileutil
执行此任务,Tcl核心命令即可。但是,让我们一起使用fileutil
。
您的代码是
package require fileutil
set pattern {data}
set filename test.txt
proc processContents {fileContents} {
return [string map {(1 2 3) {3 2 1}}] $fileContents
}
fileutil::updateInPlace test.txt processContents
这是一个公平的开始,但由于几个原因而行不通。
一个问题是,参数to的结尾括号return
应位于的右边$fileContents
,而不是它的左边。
另一个问题是,提供给其的替换列表string map
没有说“用3 2 1替换(1 2 3)”,而是说“用3 2 1替换(1和2和3)”。这是因为,如果您是美国人,则用圆括号将圆括号括起来,或者将括号括起来,在这里没有任何语法意义,它们只是文本。2周围没有引号的空格表示文本的这一部分是三个列表元素,而不是一个。要制作(1 2 3)
单个列表元素,您需要用引号将它们引起来,例如以下其中之一:
(1\ 2\ 3)
"(1 2 3)"
{(1 2 3)}
我怀疑您无论如何都不想要括号,因此该行应为:
return [string map {{1 2 3} {3 2 1}} $fileContents]
现在,定义一个单独的updateInPlace
调用命令通常是一个好主意,如果处理很复杂(基本上是一个以上的命令),则需要这样做。但是在这种情况下,您仅执行一个简单的操作。Tcl语法的优点在于可以轻松地汇编命令。如果给出updateInPlace
命令的一半,它将通过向其中添加文件的内容来完成命令,执行命令并用结果替换文件的内容。
假设您有一个仅包含string的文件foo bar
。如果您想1)打印出来并2)清除文件的内容,则可以调用
fileutil::updateInPlace test.txt puts
该updateInPlace
命令将读取文件的内容并将其附加到单词上puts
,并在单词之间添加一个空格,以产生调用puts {foo bar}
。该字符串将被打印,结果(即空字符串)将被写回到文件中,以替换先前的内容。
您提供的命令的一半可以包含其他参数,只要文件的内容适合作为最后一个参数即可。例如,您可以将内容复制到其他位置,另一个打开的文件或通过套接字:
fileutil::updateInPlace test.txt "puts $channel"
将内容发送到$channel
连接频道标识符的任何地方。
您可能会猜到我要怎么做。
fileutil::updateInPlace test.txt {string map {{1 2 3} {3 2 1}}}
是执行所需处理所需的全部。
如果您希望能够轻松更改模式以匹配并仍然用其反向替换,则可以执行以下操作:
set pattern {1 2 3}
fileutil::updateInPlace test.txt [list string map [list $pattern [lreverse $pattern]]]
除了:您什么时候用大括号将命令引起来,什么时候应该使用双引号,为什么要使用该list
命令?
简而言之:如果您需要替换命令字符串中的任何内容,请使用引号或list
。如果不这样做,则可以使用花括号。如果您需要进行替换但还要保留列表结构,则必须使用list
。所以:
puts ;# one word: you don't need to use any of the above
{puts} ;# but any one of them will do
{puts -nonewline} ;# two words: you need to wrap it: any method will do
"puts $f" ;# two words, need to substitute: quotes or list will do
您可以通过打印命令来检查命令的外观:
puts "string map {$pattern [lreverse $pattern]}"
# => string map {1 2 3 3 2 1}
在这里丢失了必要的列表结构。失败。(这是我之前写的。)
puts [list string map [list $pattern [lreverse $pattern]]]
# => string map {{1 2 3} {3 2 1}}
列表结构被保留。分数!(由Donal Fellows修复。)
这样做fileutil
(没有错误处理):
set f [open test.txt r]
set fileContents [chan read -nonewline $f]
chan close $f
set f [open test.txt w]
chan puts -nonewline $f [string map {{1 2 3} {3 2 1}} $fileContents]
chan close $f
由于操作更为基本,因此该版本的时间更长。该脚本两次打开文件:一次用于读取,将内容放入变量中fileContents
,一次用于写入,将转换后的内容放入文件中。
稍微冗长一些:
set f [open test.txt r+]
chan puts -nonewline $f [string map {{1 2 3} {3 2 1}} [chan read -nonewline $f][chan seek $f 0;list]]
chan close $f
此版本将打开文件以供读取和写入。的内容从不存储在任何可变的,但直接从管道chan read
通过string map
向chan puts
其中写入变换内容备份到文件中。(这chan seek $f 0;list
是一种技巧,可以潜入必须将写入位置重置为文件开头的位置。)
文档:chan,fileutil,list,open,package,proc,puts,return,set,string
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句