Усечение Perl Off-by-2 при выводе номера строки для усеченной строки

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

Однако усеченный вывод строки отличается от 2. Вот что происходит в моем коде:

Rain , строка, находится в строке 1 входного текстового файла (см. ниже). Применено регулярное выражение s/.{4}\K.*//s для усечения до 4, а Rain выходные данные усечены, даже если они не были усечены (Rain — это 4 символа, их не нужно сокращать). К тому же бывает за 5, s/.{5}\K.*//s.

Правильно, код выводит усеченную строку при усечении на 3 или меньше.

Как я могу показать, что при использовании s/.{4}\K.*//s и s/.{5}\K.*//s не происходит усечения? Другими словами, когда я запускаю свой код для усечения 4 или 5, Rain не отображает вывод усечения для номера строки.

Мой текстовый файл - weather.txt:

Rain
Snow

Вот мой код:

#!/usr/bin/perl
use strict;
use warnings;

my $input = 'weather.txt';

open my $fhIn, '<', $input or die qq(Unable to open "$input" for input: $!);

my @lines;

while( <$fhIn>) {
    chomp(@lines);
    push @lines, $. if s/.{5}\K.*//s;
}

my $max = @lines;
my $none = '-';

my $fmt = "%-20s\n";

print sprintf($fmt, "Column 1");

foreach my $i (0..$max-1) {
    print sprintf($fmt, ($lines[$i] or $none), ($lines[$i] or $none));
}

person Minimalist    schedule 27.09.2018    source источник


Ответы (1)


Скорее всего, ваш текстовый файл содержит возврат каретки и символ перевода строки в конце каждой строки. Вызов chomp удаляет только символ перевода строки, оставляя вам 5 символов в ваших строках.

Хорошим подходом является print ваш ввод с некоторыми разделителями вокруг него, чтобы проверить его:

print "<<$_>>\n";

Кроме того, вы можете использовать Data::Dumper для проверки ваших данных:

use Data::Dumper;
$Data::Dumper::Useqq = 1;
print Dumper $_;

Лично мне очень нравится удалять все пробелы в конце строк ввода, так как в любом случае это редко требуется:

while( <$fhIn> ) {
    s/\s+$//;
    push @lines, $. if s/.{5}\K.*//s;
};
person Corion    schedule 27.09.2018
comment
Это сработало. Большое спасибо. Также проверим дамп данных. - person Minimalist; 27.09.2018
comment
Вы также можете использовать s/\R\z// в Perl 5.10+, чтобы правильно удалить последовательность CRLF или только CR или LF. В качестве примечания chomp() удаляет только \n, потому что в Windows слой :crlf применяется к дескрипторам по умолчанию, который преобразует CRLF в \n при чтении. Вы можете применить этот слой самостоятельно, если ожидаете такие окончания строк в системе, отличной от Windows. - person Grinnz; 27.09.2018
comment
Большинство из нас очень расслабляются, когда понимают перевод строки, возврат каретки и другие пробелы. Спасибо @Grinnz за дополнительную информацию. - person Minimalist; 27.09.2018