Текстовые строки пропускаются при чтении файла построчно в Perl. ‹cr› ‹lf› несоответствие

Я хочу извлечь и зарегистрировать различные параметры модема 3G, так как есть периодические пропадания. Таким образом, я использую wget для чтения 3Ginfo.html с модема 3G и помещаю содержимое в файл contents.txt. Использование Notepad++ для открытия этого файла показывает все данные.

Из-за моей репутации я не могу размещать изображения, поэтому приведенный ниже код — лучшее, что я могу сделать; из Notepad ++ (с включенным просмотром всех символов) я получаю:

<tr>[LF]

<td class='hd'>Signal Strength:</td>[LF]

<td>[LF]

-72[CR]

&nbsp(dBm)&nbsp(High)</td>[LF]

</tr>[LF]

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

Вот код Perl для чтения файла:

open hLOGFILE, "<output.txt";
while (<hLOGFILE>) 
{ 
    print "Line no $.  Text is $_ ";
}

Вот результат (в виде текста, потому что я пока не могу размещать изображения):

Line no 98  Text is <tr>

Line no 99  Text is <td class='hd'>Signal Strength:</td>

Line no 100  Text is <td>

&nbsp(dBm)&nbsp(High)</td>

Line no 102  Text is </tr>

Ясно, что есть пропущенные строки, и это связано с терминатором конца строки <cr>. Я попытался проглотить файл, и строки все еще отсутствуют.

Помимо чтения байт за байтом, а затем попытки разобрать файл таким образом (что не очень привлекательно), я не могу найти решения.

Мой план состоит в том, чтобы просто извлекать и регистрировать интересующие строки каждую минуту или около того.

Я попытался открыть файл, указав различные кодировки, но все равно не радуюсь. Если Notepad++ может читать и отображать все данные, почему он не работает в Perl? При использовании more из командной строки Windows XP это показывает, что данные также отсутствуют.

Когда я просматриваю исходный код из хрома, я получаю

<tr>
    <td class='hd'>Received Signal Code Power(RSCP):</td>
    <td align='center'> -78 dBm</td>
</tr>

person Ornea    schedule 01.03.2013    source источник


Ответы (3)


Строка -72[CR] отсутствует. Вы просто этого не видите.

Это связано с тем, что это не строка, поскольку символ возврата каретки обычно не распознается как символ разрыва строки. Происходит то, что вы читаете это как одну строку:

-72[CR]&nbsp(dBm)&nbsp(High)</td>[LF]

И происходит то, что вы печатаете:

Line No. 101 is -72

Затем печатается этот символ возврата каретки, который заставляет курсор вернуться к началу строки. Затем печатается остальная часть строки. Это скрывает то, что вы распечатали, и, таким образом, вы видите:

&nbsp(High)</td>

потому что это перезаписало предыдущий текст в этой строке.

Я использовал VI для создания трех разных файлов с тремя разными форматами файлов ("mac" = "\r", "unix" = "\n" и "dos" = "\r\n"), затем я использовал Unix cat, чтобы объединить их в один испорченный файл.

Вот моя программа:

use 5.12.0;
use autodie;

open my $test_fh, "<:crlf", "new_test";

local ($/);               #Enable "slurp" mode
my $file = <$test_fh>;    #Whole file is read in.

$file =~ s/[\r\n]+/\n/g;  #Make all line endings just \n

#
# Now "rewrite" the file
#
my @file = split /\n/, $file;
for my $line (@file) {
    say qq(Line: "$line");
}

Это распечатывает:

Line: "MAC FILE"
Line: "this"
Line: "is"
Line: "a"
Line: "test of my"
Line: "program"
Line: "this"
Line: "WINDOWS FILE"
Line: "is"
Line: "a"
Line: "test of my"
Line: "program"
Line: "UNIX FILE"
Line: "this"
Line: "is"
Line: "a"
Line: "test of my"
Line: "program"

Как видите, в MAC-ФАЙЛЕ были показаны все строки, но слово Line: распечаталось не во всех из них. Это потому, что Perl читал его как одну большую строку. Мой s/\r+/\n/g преобразовал его для печати в несколько строк, но цикл while прочитал его как одну строку.

Взгляните на мое заявление open. Я использую три параметра, которые решают некоторые незначительные проблемы в Perl. Приятно то, что вы можете прикреплять слои или кодировки к файлу. Например, <:crlf автоматически преобразует файлы Windows с окончания \r\n только в \n, но не затрагивает файлы Unix. Это спасение для тех, кто работает в смешанных средах Unix/Windows.

Я надеялся найти аналогичный слой для старых текстовых файлов в стиле Mac (до появления Mac OS X файлы Macintosh заканчивались только \r, а не \n вообще. Это действительно решило бы проблему). К сожалению, я не нашел никакой документации по нему.Прошло много времени с тех пор, как у вас были текстовые файлы до OS X Macintosh.

person David W.    schedule 01.03.2013
comment
Потрясающе, спасибо. Это была проблема - person Ornea; 01.03.2013

Возврат каретки \r. Он указан в perldoc perlreref. Удаление его из вашего ввода, например, в этом вашем цикле, можно сделать так:

while (<hLOGFILE>) { 
    s/\r//g;
    print "Line no $.  Text is $_ ";
}

Альтернативы

tr/\r//d;        # same thing as above, really
s/[\r\n]+$//;    # remove all line endings
person TLP    schedule 01.03.2013

Вы могли бы chomp() это прочь...

open hLOGFILE, "<output.txt";
while (<hLOGFILE>)
{
    chomp(); 
    print "Line no $.  Text is $_ \n" if( $_ );
}

В некоторых системах я видел необходимость вызывать chomp() дважды, чтобы избавиться от нескольких символов конца строки... да, они существуют. Возможно, вы захотите добавить что-нибудь, чтобы удалить все эти HTML-теги? См.: Как я могу удалить HTML из строки с помощью Perl. ?

person Jim Black    schedule 01.03.2013
comment
chomp() и несколько chomp() в этом случае не помогли. Спасибо - person Ornea; 01.03.2013