在Perl中逐行读取文件时,会遗漏文本行。 <cr> <lf>不匹配</lf> </cr>

时间:2013-03-01 01:51:42

标签: perl eol

我想从3G调制解调器中提取和记录各种参数,因为存在间歇性丢失。因此我使用wget从3G调制解调器读取3Ginfo.html并将内容放入文件contents.txt。使用Notepad ++打开此文件会显示所有数据。

由于我的声誉,我无法发布图片,因此下面的代码是我能做的最好的;从Notepad ++(打开View All Characters),我得到:

<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中不起作用。从Windows XP命令行使用more时,它会显示数据也丢失。

当我从chrome查看来源时,

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

3 个答案:

答案 0 :(得分:1)

-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 FILE 确实显示了所有行,但单词Line:没有打印出所有行。那是因为Perl把它读成一条大线。我的s/\r+/\n/g将其转换为多行打印,但while循环将其作为单行读取。

查看我的open声明。我使用三个参数来解决Perl中的一些小问题。好处是你可以将图层或编码附加到文件。例如,<:crlf会自动将Windows文件从\r\n结尾转换为\n,但不会触及Unix文件。对于那些在混合Unix / Windows环境中工作的人来说,这可以节省生命。

我希望为旧的 Mac 样式的文本文件找到一些类似的图层(在Mac OS X之前的几天,Macintosh文件仅以\r结束而没有{{1}这真的解决了这个问题。不幸的是,我没有找到任何文档。自从你有OS X之前的Macintosh文本文件以来已经有很长一段时间了。

答案 1 :(得分:0)

回车符\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

答案 2 :(得分:0)

你可以把它扼杀()...

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

在某些系统上,我已经看到需要调用chomp()两次,以摆脱多个行尾字符......是的确存在。您可能还想添加一些内容来删除所有这些HTML标记?请参阅:How can I strip HTML in a string using Perl?