在Perl中,如何处理多行

时间:2010-07-10 11:14:53

标签: perl

说,我有一个文件,其中包含以下行,其中包含“TIMESTAMP”“NAME”:

10:00:00鲍勃 11:00:00汤姆 11:00:20弗雷德 11:00:40乔治
12:00:00比尔

我想读取这个文件,将每个小时中出现的名称分组到一行,然后将修改后的行写入文件,例如。

10:00:00鲍勃 11:00:00汤姆,弗雷德,乔治 12:00:00比尔

4 个答案:

答案 0 :(得分:2)

在这样的块中逐行读取文件:

while(<>) {
    # ... do something with the line in $_
    # specifically, collect the hour and name
    # ignoring malformed lines
    if (/(\d\d):\d\d:\d\d\s+(\w+)/) {
        my $hour = $1;
        my $name = $2;
    }
}

并通过在内部if

中插入以下内容来构建第一位的哈希
$people{$hour} = $people{$hour} . ", " . $name 

最后,在循环外部,打印哈希:

while ( my ($time, $names) = each(%people) ) {
    print $time . ":00:00 " . $names ."\n";
}

(这是未经测试的,但这是我将采取的基本方法。)

答案 1 :(得分:2)

在下面的grouped_by_hour中,对于文件句柄中的每一行,如果它有时间戳和名称,我们push使用sprintf命名到与时间戳小时相关联的数组上如果一个时间戳为03:04:05而另一个时间戳为3:9:18,则将小时标准化。

sub grouped_by_hour {
  my($fh) = @_;

  local $_;
  my %hour_names;

  while (<$fh>) {
    push @{ $hour_names{sprintf "%02d", $1} } => $2
      if /^(\d+):\d+:\d+\s+(.+?)\s*$/;
  }

  wantarray ? %hour_names : \%hour_names;
}

标准化小时数也允许我们使用默认比较进行排序。下面的代码将输入放在DATA令牌之后的特殊__DATA__文件句柄中,但在实际代码中,您可以调用grouped_by_hour $fh

my %hour_names = grouped_by_hour \*DATA;
foreach my $hour (sort keys %hour_names) {
  print "$hour:00:00 ", join(", " => @{ $hour_names{$hour} }), "\n";
}

__DATA__
10:00:00 Bob
11:00:00 Tom
11:00:20 Fred
11:00:40 George
12:00:00 Bill

输出:

10:00:00 Bob
11:00:00 Tom, Fred, George
12:00:00 Bill

答案 2 :(得分:2)

考虑到这一点,根据原始问题的评论,同一小时的所有条目都是连续的,文件太大而无法放入内存中,我会完全免除哈希 - 如果原始文件太大而不适合内存,然后包含其所有数据的哈希可能也会太大。 (是的,它正在压缩数据,但散列本身会增加大量开销。)

我的解决方案,然后:

#!/usr/bin/env perl

use strict;
use warnings;

my $current_hour = -1;
my @names;

while (my $line = <DATA>) {
  my ($hour, $name) = $line =~ /(\d{2}):\d{2}:\d{2} (.*)/;
  next unless $hour;

  if ($hour != $current_hour) {
    print_hour($current_hour, @names);
    @names = ();
    $current_hour = $hour;
  }

  push @names, $name;
}

print_hour($current_hour, @names);

exit;

sub print_hour {
  my ($hour, @names) = @_;
  return unless @names;

  print $hour, ':00:00 ', (join ', ', @names), "\n";
}

__DATA__
10:00:00 Bob
11:00:00 Tom
11:00:20 Fred
11:00:40 George
12:00:00 Bill

答案 3 :(得分:0)

以下是完整的解决方案。

my @readings = (
    "10:00:00 Bob",
    "11:00:00 Tom",
    "11:00:20 Fred",
    "11:00:40 George",
    "12:00:00 Bill",
);

my %hours;

for my $line (@readings) {
    $line =~ /^(\d{2}).*?([a-zA-Z]+)/;
    push(@{$hours{$1}}, $2);
}

for my $hour (sort keys %hours) {
    print "$hour:00:00 ";
    print join ", ", @{$hours{$hour}};
    print "\n";
}

这导致:

10:00:00 Bob
11:00:00 Tom, Fred, George
12:00:00 Bill