Чтение содержимого текстового файла от смещения до конца в Perl - PullRequest
0 голосов
/ 22 декабря 2011

Я учу себя Perl и Regex, читая превосходные Джеффри Фридла Освоение регулярных выражений .

При попытке выполнить упражнение «Утилита небольшой почты», начиная со стр. 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;

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

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

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

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

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

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

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

Ответы [ 3 ]

2 голосов
/ 22 декабря 2011

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

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

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

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

Это также завершит цикл, поскольку он достиг eof.

1 голос
/ 22 декабря 2011

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

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" и, если читается первый пустой символ новой строки, он переключается в состояние "body" и просто добавляет тело к переменной.

В качестве альтернативы вы можете просто вылить оставшуюся рукоятку MYFILE в тело в конце вашей исходной петли while и перед 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 голосов
/ 22 декабря 2011

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

local $/;
$body = <MYFILE>;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...