使用Tcl解析文件

时间:2011-03-25 06:12:18

标签: tcl

我这里有一个文件,里面有多个set语句。但是,我想提取我感兴趣的行。以下代码可以帮助

set in [open filename r]    
seek $in 0 start    
while{ [gets $in line ] != -1} {    
    regexp (line to be extracted)
}

6 个答案:

答案 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
 }