Разбор файла с Tcl - PullRequest
       5

Разбор файла с Tcl

2 голосов
/ 25 марта 2011

У меня есть файл, в котором есть несколько операторов set.Однако я хочу извлечь интересующие меня строки.Может ли следующий код помочь

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

Ответы [ 6 ]

8 голосов
/ 25 марта 2011

Другое решение:

Вместо использования 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 - это полный путь к файлу, если файл не находится в том же каталоге, где находится программа.

3 голосов
/ 25 марта 2011

Во-первых, вам не нужно 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 использовать для определенных типов входных данных, задайте дополнительные вопросы здесь по переполнению стека.

1 голос
/ 28 марта 2011

Еще одно решение:

похоже, что источником является сценарий TCL, создайте новый безопасный интерпретатор, используя interp , в котором выставлена ​​только команда set (и любые другие необходимые вам), скройте все остальные команды и замените неизвестно чтобы просто пропустить что-то нераспознанное. источник вход в этот интерпретатор

0 голосов
/ 05 марта 2014
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
 }
0 голосов
/ 03 апреля 2011

До сих пор я читал ваши комментарии, и, если я правильно вас понял, ваш файл входных данных содержит 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 голосов
/ 26 марта 2011

Вот еще одно решение: используйте функцию сканирования файлов 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

Еще одно решение: используйте команду grep из пакета fileutil:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...