我这里有一个文件,里面有多个set语句。但是,我想提取我感兴趣的行。以下代码可以帮助
set in [open filename r]
seek $in 0 start
while{ [gets $in line ] != -1} {
regexp (line to be extracted)
}
答案 0 :(得分:7)
其他解决方案:
而不是使用gets
我更喜欢使用read
函数来读取文件的全部内容,然后逐行处理。因此,我们通过将其作为行列表来完全控制文件操作
set fileName [lindex $argv 0]
catch {set fptr [open $fileName r]} ;
set contents [read -nonewline $fptr] ;#Read the file contents
close $fptr ;#Close the file since it has been read now
set splitCont [split $contents "\n"] ;#Split the files contents on new line
foreach ele $splitCont {
if {[regexp {^set +(\S+) +(.*)} $ele -> name value]} {
puts "The name \"$name\" maps to the value \"$value\""
}
}
如何运行此代码:
说上面的代码保存在test.tcl
中
然后
tclsh test.tcl FileName
FileName
是文件的完整路径,除非该文件位于程序所在的目录中。
答案 1 :(得分:3)
首先,在打开文件进行阅读后,您不需要seek
直到开头;这就是它开始的地方。
其次,读取文件的模式是:
set f [open $filename]
while {[gets $f line] > -1} {
# Process lines
if {[regexp {^set +(\S+) +(.*)} $line -> name value]} {
puts "The name \"$name\" maps to the value \"$value\""
}
}
close $f
好的,这是一个非常简单的RE在中间(对于更复杂的文件,你需要几个),但这是一般模式。请注意,与Tcl一样,while
命令字之后的空格很重要,while表达式和while体之间的空间也很重要。有关用于特定类型输入数据的RE的具体帮助,请在Stack Overflow上询问更多问题。
答案 2 :(得分:1)
又一个解决方案:
因为看起来源是一个TCL脚本,使用interp创建一个新的安全解释器,它只暴露set命令(以及你需要的任何其他命令),隐藏所有其他命令并替换{{3}只是跳过任何未被识别的东西。 unknown此解释器中的输入
答案 3 :(得分:0)
这是另一种解决方案:使用Tclx的文件扫描功能。请查看Tclx以获取更多信息。我喜欢这个解决方案,你可以有几个scanmatch块。
package require Tclx
# Open a file, skip error checking for simplicity
set inputFile [open sample.tcl r]
# Scan the file
set scanHandle [scancontext create]
scanmatch $scanHandle {^\s*set} {
lassign $matchInfo(line) setCmd varName varValue; # parse the line
puts "$varName = $varValue"
}
scanfile $scanHandle $inputFile
close $inputFile
另一个解决方案:使用fileutil包中的grep命令:
package require fileutil
puts [lindex $argv 0]
set matchedLines [fileutil::grep {^\s*set} [lindex $argv 0]]
foreach line $matchedLines {
# Each line is in format: filename:line, for example
# sample.tcl:set foo bar
set varName [lindex $line 1]
set varValue [lindex $line 2]
puts "$varName = $varValue"
}
答案 4 :(得分:0)
到目前为止,我已经阅读了您的评论,如果我理解正确,您的输入数据文件每行有6个(或9个,取决于哪个评论)数据字段,用空格分隔。您希望使用正则表达式将它们解析为6(或9)个数组或列表,每个数据字段一个。
如果是这样,我会尝试这样的事情(使用列表):
set f [open $filename]
while {[gets $f line] > -1} {
# Process lines
if {[regexp {(\S+) (\S+) (\S+) (\S+) (\S+) (\S+)} $line -> name source drain gate bulk inst]} {
lappend nameL $name
lappend sourceL $source
lappend drainL $drain
lappend gateL $gate
lappend bulkL $bulk
lappend instL $inst
}
}
close $f
现在你应该有一组6个列表,每个字段一个,列表中有一个条目用于输入文件中的每个项目。例如,要访问第i个名称,请抓取$nameL[$i
]。
如果(我怀疑)你的主要目标是获取名称为“foo”的设备的参数,你将使用这样的结构:
set name "foo"
set i [lsearch $nameL $name]
if {$i != -1} {
set source $sourceL[$i]
} else {
puts "item $name not found."
set source ''
# or set to 0, or whatever "not found" marker you like
}
答案 5 :(得分:0)
set File [ open $fileName r ]
while { [ gets $File line ] >= 0 } {
regex {(set) ([a-zA-Z0-0]+) (.*)} $line str1 str2 str3 str4
#str2 contains "set";
#str3 contains variable to be set;
#str4 contains the value to be set;
close $File
}