arrays - 在 perl 中使用正则表达式合并相似的行

标签 arrays regex perl merge

您好,我正在对文件进行排序,我想通过将相似的行合并在一起来使其更易于阅读。数据已经根据每行的第一个单词按字母顺序排序。到目前为止,我的程序仅将行读入数组并打印出来。

文本文件包含:

Network ubuntu Jan  1 13:42:13 : <info>  DHCP: device eth5 state changed bound -> renew Network
Network ubuntu Jan  2 13:42:42 : <info>    prefix 24 (255.255.255.0) Network
Network ubuntu Jan  2 12:11:42 : <info>  DHCP: device eth5 state changed bound -> renew Network
testing ubuntu Jan  1 01:13:42 : DHCPACK of 192.168.233.129 from 192.168.233.254 testing
testing ubuntu Jan  2 13:54:42 : DHCPACK of 192.168.233.129 from 192.168.233.254 testing
testing ubuntu Jan  3 13:02:42 : DHCPACK of 192.168.233.129 from 192.168.233.254 testing

我的程序:

#!/usr/bin/perl 

$FILE = '/computer/testfile.txt';
open(INFO, $FILE);

while($line = <INFO>){
    push(@array, $line);
}

print @array;

我想使用正则表达式合并任何相同的行,不包括日期/时间戳。结果是在括号中包含合并的行数,然后是最早和最晚的日期/时间戳。如果没有相似的行,它会忽略保持不变的行。

预期的最终结果

Network ubuntu Jan  2 13:42:42 : <info>    prefix 24 (255.255.255.0) Network
Network ubuntu (2) Jan  1 13:42:13-Jan  2 12:11:42: <info>  DHCP: device eth5 state changed bound -> renew Network
testing ubuntu (3) Jan  1 01:13:42-Jan  3 13:02:42 : DHCPACK of 192.168.233.129 from 192.168.233.254 testing 

如有任何帮助或指导,我们将不胜感激。谢谢

最佳答案

您可以使用 Time::Piece解析日期。请注意,如果没有年份,您就无法真正对时间戳进行排序。

只需逐行读取排序后的文件即可。如果信息与上一行相同,则累加时间戳,否则输出前一次累加的信息,开始累加新的信息。

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

use Time::Piece;


sub output {
    my ($pre, $post, @timestamps) = @_;
    if (@timestamps > 1) {
        @timestamps = map $_->[0],                 # Use Schwartzian Transform to sort by timestamp.
                      sort { $a->[1] <=> $b->[1] }
                      map [ $_, 'Time::Piece'->strptime($_, '%b %d %H:%M:%S') ],
                      @timestamps;
        print "$pre (", scalar @timestamps, ") ",
              $timestamps[0], '-', $timestamps[-1],
              $post, "\n";
    } else {
        print "$pre$timestamps[0]$post\n";
    }
}


my @last;
my @timestamps;
while (<>) {
    my ($pre, $timestamp, $post)
        = /(.*?) ([ADFJMNOS][aceopu][bcglnprtvy]\s+[0-9]+\s[0-9:]+) (.*)/x;

    if (@last and $pre eq $last[0] and $post eq $last[1]) {
        push @timestamps, $timestamp;

    } else {
        output(@last, @timestamps) if @timestamps;
        @last = ($pre, $post);
        @timestamps = ($timestamp);
    }
}
output(@last, @timestamps); # Don't forget to output the last batch.

关于arrays - 在 perl 中使用正则表达式合并相似的行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27750320/

相关文章:

C++ 将 char** 分配给字符串数组

c# - 如何将单个等号与正则表达式匹配?

perl - 如何在没有 root 访问权限的情况下在本地安装 CPAN 模块(DynaLoader.pm 第 229 行错误)?

mysql - Perl DBI MySQL 错误消息 : Can't call method "do" on an undefined value

javascript - 如果名称值为空,我需要将其更改为Javascript中数组的末尾

java - byte[] 不会解析为图像

javascript - 获取选择器中数组的最后 2 个元素 (Redux)

ios - 在 Swift 3 中使用 switch 语句构建正则表达式

php - 正则表达式和xpath查询

perl - CR vs LF perl 解析