2011-03-25 80 views
1

我在這裏有一個文件,它有多個set語句。但是,我想提取我感興趣的內容。可以將下面的代碼幫助用Tcl解析文件

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

回答

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 

OK,這中間有一個很簡單的RE(和更復雜的文件,你需要一些),但是那一般模式。請注意,與Tcl一樣,while命令字之後的空格很重要,while表達式和while body之間的空格也很重要。有關特定類型的輸入數據使用什麼RE的具體幫助,請在Stack Overflow上提出進一步的問題。

+0

感謝名單4回合的幫助........ ill c 2 it ..... – Naaz 2011-03-25 10:29:47

+0

我有如下幾行...... set name some string set othername some otherstring .... and soon – Naaz 2011-03-25 10:41:02

+0

@ Nazeeb:嘗試上面更改的版本。拆分這些行以便獲得'$ name'和'$ value'。我的樣品只是將它們打印出來;添加代碼來做一些更聰明的... – 2011-03-25 10:46:16

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是文件的完整路徑,除非文件位於程序所在的同一目錄中。

+0

錯誤:不能讀取fptr – Naaz 2011-03-28 05:20:10

+0

提取的行是......」man.poi oa vs vs 0.9 0.09「...我不認爲該正則表達式將工作 – Naaz 2011-03-29 06:07:08

+0

您是否在運行程序時給出了文件名作爲參數?由於打開的函數未找到該文件,因此出現錯誤。 – vaichidrewar 2011-03-30 14:41:15

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" 
} 

+0

是否可能在TCL中使用腳本代替TCLx – Naaz 2011-03-28 05:14:26

+0

@Nazeeb:這仍然是TCL,但是在Tclx包的幫助下。如果您不想使用Tclx,請查看其他解決方案。我希望我能正確理解你的問題。 – 2011-03-28 15:10:27

1

又一解決方案:

因爲它看起來像源是TCL腳本,創建一個使用interp的新安全解釋器,它只有暴露的設置命令(以及任何你需要的其他命令),隱藏所有其他命令並替換unknown以跳過任何未完成的命令gnised。 source在這個翻譯器的輸入

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