#tcl
#tcl
Вопрос:
Я читаю файл и произвожу некоторые манипуляции с данными. К сожалению, я получаю следующее сообщение об ошибке:
невозможно выделить 347392 байта Прервать
Поскольку файл огромен, я хочу читать только те строки, которые содержат какое-то слово (описать в «regexp_or «).
Есть ли какой-нибудь способ прочитать только строки, содержащие «regexp_or», и сохранить цикл foreach?
set regexp_or "^Err|warning|Fatal error"
set file [open [lindex $argv 1] r]
set data [ read $file ]
foreach line [ split $data "n" ] {
if {[regexp [subst $regexp_or] $line]} {
puts $line
}
}
Ответ №1:
Вы могли бы внести свой вклад через grep
:
set file [open |[list grep -E $regexp_or [lindex $argv 1]] r]
Но это зависит от grep
того, насколько вы доступны. Чтобы сделать это полностью в Tcl, вы можете обрабатывать файл по частям:
set file [open [lindex $argv 1] r]
while {![eof $file]} {
# Read a million characters
set data [read $file 1000000]
# Make sure to only work with complete lines
append data [gets $file]
foreach line [lsearch -inline -all -regexp [split $data n] $regexp_or] {
puts $line
}
}
close $file
Комментарии:
1. Конечно, вы также можете просто обрабатывать файл построчно, используя
gets
, но это, вероятно, намного медленнее (примечание: я на самом деле не измерял).2. Я бы не ожидал, что это будет значительно медленнее, так как буферизация выполнена правильно, но я никогда не тестировал. У меня также нет подходящего входного корпуса для проведения такого теста…
3. Я только что провел быстрый тест на файле размером 30 МБ, подсчитав совпадения (их было 3645). Фрагментированный подход был примерно на 12% быстрее. Я провел тест несколько раз для каждого подхода и сравнил самое короткое время каждого из них.