如何解决Perl:编辑日志文件数据
我有一个像这样(以下)的表结构形式的日志文件,并想在其中编辑相同的send-id列。我刚接触perl并尝试过,但无法获得想要的东西。
Code send_id dest_id
AW 96 45
BX 65 96
现在在这里,我必须将send_id列ID修改为名称(例如96 = Alex和65 = James)并重新生成日志文件,如下所示格式[在此处输入图像描述] [2]。
Code send_id dest_id
AW Alex 45
BX James 96
我一直到这里都没有得到想要的输出,我正在逐行阅读。 我越来越像这样
Code send_id dest_id
AW Alex 45
James
谁能告诉我该怎么做?
谢谢。
#!/usr/bin/perl
use warnings;
use strict;
my $log_file = "/home/ajay/Desktop/log.log";
open(Log1,"<$log_file") or die ("Could not open");
open(Log2,">$log2.pl");
while ($a=<Log1>) {
if ($a =~ /65/){
$a = "James";
print Log2"$a\n";
}
else {
print Log2"$a";
}
}
close Log2;
close Log1;
解决方法
您可以使用以下方法在当前行中替换替换值:
while (my $line = <$Log1>) {
chomp $line;
if ($line =~ /65/){
$line =~ s/65/James/;
}
say $Log2 $line;
}
但是,更好的方法是保留不同替换值的哈希值。例如这样的
use 5.22.0;
use strict;
use warnings;
use experimental qw(refaliasing);
my $log_file = "/home/ajay/Desktop/log.log";
my $log2_file = "/home/ajay/Desktop/log2.log";
open( my $Log1,"<",$log_file ) or die "Could not open file $log_file: $!";
open ( my $Log2,">",$log2_file) or die "Could not open file $log2_file: $!";
while (my $line = <$Log1>) {
my @fields = split " ",$line;
next if @fields != 3;
\my $id = \$fields[1];
if ( exists $id_map{$id} ) {
$id = $id_map{$id};
}
say $Log2 (join "\t",@fields);
}
close $Log2;
close $Log1;
更新:
要使输出字段居中,您可以尝试:
my %id_map = ("65" => "James","96" => "Alex");
open( my $Log1,$log_file ) or die "Could not open file $log_file: $!";
my $field_width = 20;
my $num_fields = 3;
open ( my $Log2,$log2_file) or die "Could not open file $log2_file: $!";
my $sep_line = ("-" x ($num_fields * $field_width));
while (my $line = <$Log1>) {
my @fields = split " ",$line;
next if @fields != $num_fields;
\my $id = \$fields[1];
if ( exists $id_map{$id} ) {
$id = $id_map{$id};
}
say $Log2 $sep_line if $. == 1;
say $Log2 (join " ",map {align($_,$field_width)} @fields);
say $Log2 $sep_line if $. == 1;
}
close $Log2;
close $Log1;
sub align {
my ( $str,$field_width ) = @_;
my $len = length $str;
if ($len >= $field_width) {
return $str;
}
else {
my $left = int(($field_width - $len) / 2);
my $right = $field_width - $left - $len;
my $str = (" " x $left) . $str . ( " " x $right );
return $str;
}
}
输出:
------------------------------------------------------------
Code send_id dest_id
------------------------------------------------------------
AW Alex 45
BX James 96
,
您不太清楚文件的格式。看起来可能用制表符分隔,所以这就是我要处理的方式。如果不是这种情况,则需要对该代码进行一些小的调整。
我也摆脱了所有文件处理代码。该任务应作为Unix过滤器实现-即,它从STDIN
读取并写入STDOUT
。这使您的代码既简单又灵活。
我也使它成为数据驱动的。将新的ID /名称组合添加到%id
哈希很简单。
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
my %id = (
96 => 'Alex',65 => 'James',);
while (<>) {
chomp;
my @fields = split;
if (exists $id{$fields[1]}) {
$fields[1] = $id{$fields[1]};
say join "\t",@fields;
} else {
say;
}
}
由于它是Unix过滤器,因此可以使用I / O重定向来调用它。如果假设我们将这段代码放在一个名为edittracker
的文件中,那么我们将这样称呼它:
$ edittracker < /home/ajay/Desktop/log.log > log2.log
有关Unix过滤器模型的更多信息,请参见this article。
,您似乎具有固定的列格式。在这种情况下,unpack通常很方便将列分开。使用A
格式说明符和列宽。
有了这些列后,只需查看您关心的列并随意替换其值即可。使用相同的格式将它们与pack放在一起:
use v5.10;
my $header = <DATA>;
print $header;
my %Replacements = (
96 => 'Alex',);
my $format = 'A8 A9 A9';
while( <DATA> ) {
chomp;
my( $code,$send_id,$dest_id ) = unpack $format;
$send_id = $Replacements{$send_id} // $send_id;
say pack $format,$code,$dest_id
}
__END__
Code send_id dest_id
AW 96 45
BX 65 96
请注意,这样的打包将截断大于宽度的数据。这是输出:
Code send_id dest_id
AW Alex 45
BX James 96
,
以下代码演示了许多可能的解决方案之一。
算法
- 将
id name
对的文件读入哈希 - 读取日志文件并将字段拆分为哈希
- 用名称替换ID
- 输出更新的数据
use strict;
use warnings;
use feature 'say';
my %ids;
while( <DATA> ) { # ids
next if /^\s*\z/;
last if /__DATA__/;
my($id,$name) = split;
$ids{$id} = $name;
}
while( <DATA> ) { # log file
next if /^\s*\z/;
chomp;
if( /Code/ ) {
say join("\t",split);
} else {
my %data;
@data{qw/code send_id dest_id/} = split;
$data{send_id} = $ids{ $data{send_id} } || $data{send_id};
$data{dest_id} = $ids{ $data{dest_id} } || $data{dest_id};
say join("\t",@data{qw/code send_id dest_id/});
}
}
__DATA__
96 Alex
65 James
__DATA__
Code send_id dest_id
AW 96 45
BX 65 96
输出
Code send_id dest_id
AW Alex 45
BX James Alex