Perl读取、查找和告诉文本文件。正在读取的字节太多。层和换行处理

Perl读取、查找和告诉文本文件。正在读取的字节太多。层和换行处理,perl,seek,tell,binmode,Perl,Seek,Tell,Binmode,我有一个Perl脚本,它分析一个文本文件(可以是UNIX或windows的行尾),当它找到感兴趣的内容时,存储文件偏移量 open(my $fh, $filename); my $groups; my %hash; while(<$fh>) { if($_ =~ /interesting/ ) { $hash{$groups++}{offset} = tell($fh); } } close $fh; 打开(我的$fh,$filename); 我的$组; 我

我有一个Perl脚本,它分析一个文本文件(可以是UNIX或windows的行尾),当它找到感兴趣的内容时,存储文件偏移量

open(my $fh, $filename);
my $groups;
my %hash;
while(<$fh>) {
   if($_ =~ /interesting/ ) {
      $hash{$groups++}{offset} = tell($fh);
   }
}
close $fh;
打开(我的$fh,$filename);
我的$组;
我的%hash;
while(){
如果($\=~/interest/){
$hash{$groups++}{offset}=tell($fh);
}
}
收盘价$fh;
随后在脚本中,我希望生成文本文件的“n”个副本,但在每个“有趣”区域都有额外的内容。为了实现这一点,我通过偏移量的散列循环:

foreach my $group (keys %hash) {
   my $href = $hash{$group};
   my $offset = $href->{offset};

   my $top;
   open( $fh, $file);
   read( $fh, $top, $offset);
   my $bottom = do{local $/; <$fh>};
   close $fh;

   $href->{modified} = $top . "Hello World\n" . $bottom;
}
foreach my$组(关键字%hash){
my$href=$hash{$group};
我的$offset=$href->{offset};
我的$top;
打开($fh,$file);
读取($fh,$top,$offset);
my$bottom=do{local$/;};
收盘价$fh;
$href->{modified}=$top.“Hello World\n”。$bottom;
}
问题是read命令读取的字节太多。我怀疑这是一个行尾问题,因为输出的字节数(chars?)与行号相同。使用记事本++时,
tell()
命令将返回到感兴趣点的实际偏移量,但在
read()
中使用该偏移量值将返回超过感兴趣点的字符

open(my $fh, $filename);
my $groups;
my %hash;
while(<$fh>) {
   if($_ =~ /interesting/ ) {
      $hash{$groups++}{offset} = tell($fh);
   }
}
close $fh;
我尝试在
open()
命令之后,在
read()之前添加
binmode($fh)
。这确实在文本文件中找到了正确的位置,但随后我得到了(CR+CRLF)输出,文本文件中充满了双回车

我玩过layers:crlf,:bytes,但没有改进

有点卡住了

  • 具有连续整数范围作为键的哈希应该是数组

  • 每次出现
    /interest/

  • 听起来你需要做的就是

    open(my $fh, $filename);
    while (<$fh>) {
      print;
      print "Hello World\n" if /interesting/;
    }
    
    打开(我的$fh,$filename);
    而(){
    印刷品;
    如果/interest/,则打印“Hello World\n”;
    }
    

    • perldoc-f读取:

      read FILEHANDLE,SCALAR,LENGTH,OFFSET
      read FILEHANDLE,SCALAR,LENGTH
      
      因此,当您这样做时:

      read( $fh, $top, $offset);
      
      您的
      $offset
      实际上是一个长度。决定你需要读多少个字符<代码>读取
      不考虑行尾,它读取指定的字节数

      如果要读取一行,则不要使用
      read
      ,请使用:

      seek($fh, $offset, 0);
      $top = <$fh>;
      
      seek($fh,$offset,0);
      $top=;
      

      您的文件中是否充满了两行新行,或者您添加了一行带有
      print
      语句的新行

      当输入文件不是ginormous时,我处理这个问题的标准方法是将文件插入并规范化行尾,将每一行存储为一个数组元素。有时我不得不在同一批文件中处理Windows(
      CR
      +
      LF
      )和UNIX(
      LF
      )以及Mac(
      CR
      )行结尾。同样的脚本也需要在所有三个平台上正确运行

      当我不得不处理这样的事情时,我通常采取束带和背带的方式。一种应该有效的方法:

      sub read_file_into_array
      {
          my $file = shift;
          my ($len, $cnt, $data, @file);
      
          open my $fh, "<", $file         or die "Can't read $file: $!";
          seek $fh, 0, 2                  or die "Can't seek $file: $!";
          $len = tell $fh;
          seek $fh, 0, 0                  or die "Can't seek $file: $!";
      
          $cnt = read $fh, $data, $len;
          close $fh;
      
          $cnt == $len or die "Attempted to read $len bytes; got $cnt";
      
          $data =~ s/\r\n/\n/g;       # Convert DOS line endings to UNIX
          $data =~ s/\r/\n/g;         # Convert Mac line endings to UNIX
      
          @file = split /\n/, $data;  # Split on UNIX line endings
      
          return \@file;
      }
      

      你为什么不
      seek
      定位,只打开一次文件?
      CRLF
      不是字符。Windows文本文件的行以两个字符
      CR
      LF
      或回车和换行符结尾。很难相信您的文件“充满了双回车符”。这就是我添加binmode()时得到的结果。作为字节字符串:/*********************************************************************************/CRCRLF/*链接器脚本*/CRCRLF@Borodin事实上,这很容易让人相信。crlf正是当您使用
      :crlf
      层将
      “\r\n”
      打印到文件句柄时得到的。Perl按原样打印CR,然后将LF转换为CRLF。@cjm:可能吧,但代码中没有任何CRs打印的迹象。Chris,除了在一行末尾打印
      “\n”
      之外,你还打印其他内容吗?我已经尝试过简化我的示例,以避免混淆。是的,我需要生成一份完整文件的副本,其中附加了/interest/sections。文本文件实际上是一个链接器脚本,/interest/部分是.input部分。最后,Perl脚本将使用这些修改的链接器脚本中的每一个进行多线程调用LD。。我的问题是read()命令返回的字节太多。我本以为这是的作业,但只使用
      binmode$fh
      应该没有问题。是的,您将在行尾获得
      LF
      CR
      +
      LF
      ,具体取决于文件的来源,但是
      seek
      中的值是正确的。