Как читать построчно файл только для CR с помощью Perl?

Я пытаюсь прочитать файл, в котором в качестве разделителя строк используется только CR. Я использую Mac OS X и Perl v.5.8.8. Этот сценарий должен запускаться на каждой платформе для всех типов разделителей строк (CR, LF, CRLF).

Мой текущий код следующий:

open(FILE, "test.txt");

while($record = <FILE>){
    print $record;
}

close(TEST);

В настоящее время печатается только последняя строка (или худший вариант). Что здесь происходит? Очевидно, я бы не хотел преобразовывать файл. Является ли это возможным?


person subb    schedule 10.06.2010    source источник
comment
Я собираюсь раздражать и предлагаю вам использовать прагмы strict и warnings, они сэкономят вам часы отладки. Кроме того, лучше всего использовать современную 3-аргументную форму открытия с лексическими дескрипторами файлов. См. stackoverflow.com/questions/1479741/ для получения дополнительной информации.   -  person daotoad    schedule 11.06.2010


Ответы (2)


Вы можете установить разделитель с помощью специальной переменной $/:

local $/ = "\r" # CR, use "\r\n" for CRLF or "\n" for LF
my $line = <FILE>;

См. perldoc perlvar для получения дополнительной информации.

Другое решение, которое работает со всеми видами разрывов строк, - это сразу проглотить весь файл, а затем разбить его на строки с помощью регулярного выражения:

local $/ = undef;
my $content = <FILE>;
my @lines = split /\r\n|\n|\r/, $content;

Однако вы не должны делать этого с очень большими файлами, поскольку файл полностью считывается в память. Обратите внимание, что установка $ / на неопределенное значение отключает разделитель строк, что означает, что все читается до конца файла.

person jkramer    schedule 10.06.2010
comment
\ r - это просто пример для CR, вы можете попробовать \ r \ n и \ n для CRLF и LF соответственно. - person jkramer; 11.06.2010
comment
О, я вижу. CR и Terminal плохо сочетаются друг с другом. - person subb; 11.06.2010
comment
В вашем сплите есть ошибка. Perl будет использовать первую подходящую ветвь в чередовании и пробовать более поздние ветки только в том случае, если она не может удовлетворить полный шаблон. Итак, если $content равно "a\r\nb", результатом будет ('a', '', 'b'). Изменение чередования на /\r\n|\r|\n/ приведет к желаемым результатам, его можно упростить до /\r\n?|\n/. - person Ven'Tatsu; 11.06.2010
comment
Вы правы, я исправил. Обычно я просто использую / \ r? \ N /, но это не сработает с переносами строк в CR. Однако я никогда раньше не видел, чтобы на практике использовались только символы переноса строки. - person jkramer; 11.06.2010
comment
См. мой ответ здесь, чтобы узнать об альтернативе использования \R для разделения на любом из трех разделителей новой строки. (И да, к сожалению, есть программы для Mac, использующие CR через 20 лет после того, как он устарел) - person mivk; 05.10.2020

Я решил более общую проблему, которая может быть здесь полезна:

Как разобрать большой файл построчно с любым разделителем строк (CR / CRLF / LF), но заранее неизвестным.

«Большой» файл означает, что нельзя читать весь файл в одной переменной. Здесь функция «detectEndOfLine» получает имя файла и возвращает либо «\ r», либо «\ n», в зависимости от того, что используется для окончания строки (она искала символ «\ r» или «\ n» по символам, начиная с конец файла).

my $file = "test.txt";
local $/ = detectEndOfLine($file);
open(IN, $file) or die "Can't open file \"$file\" for reading: $!\n";
while(<IN>) {
    s/\r\n|\n|\r$//;
    print "$_\n";
}

sub detectEndOfLine {
    my $file = $_[0];
    my $size = -s $file;
    print "\"$size\"\n";

    open(IN, $file) or die "Can't open file \"$file\" for reading: $!\n";
    for(my $i = $size; $i >= 0; --$i) {
        seek(IN, $i, 0);
        $_ = <IN>;
        my $sym = substr($_, 0, 1);
        return $sym if( $sym eq "\n" or $sym eq "\r" );
    }
    return undef;
}
person dmitry    schedule 04.06.2013