2011-12-22 4 views
0

Я преподаю Perl и Regex, прочитав отличный от Jeffrey Friedl Mastering Regular Expressions.Прочитайте содержимое текстового файла со смещения до конца в Perl

При попытке решить упражнение «Утилита малой почты», начиная со страницы 53, я наткнулся на проблему не знать, как сохранить содержимое файла в переменной , начиная со смещения.

Итак, вот мой (сокращенный) сценарий.

my ($body, $line, $subject); 
$body = $line = $subject = ""; 

open(MYFILE, "king.in") || die("Could not open file!");  
# Read the file's content line by line 
while ($line = <MYFILE>) 
{ 
    # An empty line marks the beginning of the body 
    if ($line =~ m/^\s+$/) { 
     # HERE IS THE ISSUE 
     # Save the file content starting from the current line 
     # to the end of the file into $body 
     last; 
    } 

    if ($line =~ m/^subject: (.*)/i) { 
     $subject = $1; 
    } 
    # Parse additional data from the mail header 
} 
close(MYFILE); 

print "Subject: Re: $subject\n"; 
print "\n" ; 
print $body; 

Я сделал некоторые исследования в интерактивном режиме, но не мог понять, как положить оставшуюся часть файла (то есть, электронный орган) в переменную $ тела.

я понял, что я мог бы получить текущую позицию в файл в байтах, используя $pos = tell(MYFILE);

В конце концов я закончил с работой, но неудовлетворительно solution сдачи линии самого файла первой в массив.

Как сохранить содержимое файла, начиная со смещения (либо в виде строки или байта) в $ body?

Edit: Моего решения им обеспечивается vstm- является использование $body = join("", <MYFILE>) читать в остальной части файла при столкновении с пустой строкой, которая отмечает начало тела. Весь написанный мной сценарий можно найти here.

Хотя это отлично работает для меня сейчас, я все равно хотел бы знать, как сказать (элегантно) в Perl «дать мне строки от x до z этого файла».

Спасибо за советы.

ответ

1

Вместо того, чтобы немедленно останавливаться, вы можете просто установить флаг, который говорит «теперь я читаю тело». Например:

my $inbody = 0; 

while ($line = <MYFILE>) 
{ 
    if($inbody) { 
     $body .= $line; 
     next; 
    } 
    # An empty line marks the beginning of the body 
    if ($line =~ m/^\s+$/) { 
     # HERE IS THE ISSUE 
     # Save the file content starting from the current line 
     # to the end of the file into $body 
     $inbody = 1; 
     next; 
    } 

    if ($line =~ m/^subject: (.*)/i) { 
     $subject = $1; 
    } 
    # Parse additional data from the mail header 
} 

Это как мини-государственная машина. Сначала он находится в «header» -state, и если первая пустая новая строка считывается, она переключается на «body» -state и просто добавляет тело к переменной.

В качестве альтернативы вы можете просто чавкать остальную часть MYFILE -Handle в тело в конце оригинального while -loop и перед close:

# This would be your original while loop, (I've just shortened it) 
while ($line = <MYFILE>) 
{ 
    if ($line =~ m/^\s+$/) { 
     last; 
    } 
    # Parse additional data from the mail header 
} 

# The MYFILE-handle is now still valid and at the beginning of the body 
$body = join("", <MYFILE>); 

# now you can close the handle 
close(MYFILE); 
+0

'$ body = join (" ", );' сделал трюк отлично, благодаря кучу. Из любопытства: Как мне сказать «Дайте мне строки от x до z этого файла» в Perl? Должен ли я сначала поместить все строки в массив? –

0

Вы можете изменить входной разделитель записей:

local $/; 
$body = <MYFILE>; 
2

Переменная $. предоставит вам номер строки текущего дескриптора файла. Документация here.

Если вы хотите получить смещение в байтах в файле, вы можете использовать seek, чтобы установить положение дескриптора файла. Но, как правило, вы действительно не хотите этого делать, если байт на самом деле не является вашим желаемым смещением.

Простейшим решением для этого, вероятно, является использование разделителя входных данных.Установка в undef будет чавкать файл, вместо того, чтобы читать его строка за строкой:

my $text; 
my $subject; 
while (<MYFILE>) { 
    if (/^subject: /i) { # /i flag to ignore case 
     $subject = $_; 
    } elsif (/^\s*$/) { 
     local $/; 
     $text = <MYFILE>; 
    } 
} 

Это будет конец цикла, а также, так как он достиг ВФ.

+0

Спасибо, установка разделителя входных записей в undef отлично работает. Есть ли разница в производительности по сравнению с 'join (" ", )'? –

+0

@mareser Создание локальной копии - способ установить ее в undef. Я не знаю, какое решение работает лучше. Если это важно, вы всегда можете сравнить его. Поиск CPAN для эталонного модуля. – TLP

+0

А, я вижу. Я предпочитаю метод join(), поскольку он выглядит мне более знакомым, чем '$ /' (я сделал некоторое время Python). Кроме того: есть ли элегантный способ сказать «дайте мне строки от x до z этого файла»? –

Смежные вопросы