首页 > 解决方案 > Perl中如何将一个值压入数组?

问题描述

我在将一些值插入哈希数组时遇到了问题,以获得整洁的屏幕打印。

文件输入

#2.#2018 05 24 10:43:38:683#+0200#Info#/Sys/Sec/Authentication#
#BC-JAS-SEC#security#C0000A7103EC9E50000000004#common.com/irj#com.common.services.security.authentication.logincontext.table#USER1#5##C47731E44D00000bae##0#Thread[HTTP
Worker [@1473726842],5,Dedicated_Application_Thread]#Plain## Login
User: USER1 IP Address: 127.0.0.1 Authentication Stack: ticket
Authentication Stack Properties:

#2.#2018 05 24 11:05:04:011#+0200#Info#/Sy/Sec/Authentication#
#BC-JAS-SEC#security#C0000A7103EC9F50000000004#common.com/irj#com.common.services.security.authentication.logincontext.table#USER4#6##A40B81404D03c0bae##0#Thread[HTTP
Worker [@1264376989],5,Dedicated_Application_Thread]#Plain## Login
User: USER4 IP Address: 127.0.0.1 Authentication Stack: ticket
Authentication Stack Properties:

#2.#2018 05 24 11:05:07:100#+0200#Info#/Sys/Sec/Authentication#
#BC-JAS-SEC#security#C0000A7103ECA0C#3935150000000004#common.com/irj#com.common.services.security.authentication.logincontext.table#USER3#7##9ACF7Ec0bae##0#Thread[HTTP
Worker [@124054179],5,Dedicated_Application_Thread]#Plain## Logout
User: USER3 IP Address: 127.0.0.1 Authentication Stack: ticket
Authentication Stack Properties:

#2.#2018 05 24 11:07:21:314#+0200#Warn#/Sys/Sec/Authentication#
#BC-JAS-SEC#security#C0000A7103ECA20E0000508C#3935150000000004#common.com/irj#com.common.services.security.authentication.logincontext.table#USER2#03c0bae##0#Thread[HTTP
Worker [@2033389552],5,Dedicated_Application_Thread]#Plain## Login
User: USER2 IP Address: 127.0.0.1 Authentication Stack: ticket
Authentication Stack Properties:

#2.#2018 05 02 10:48:05:700#+0200#Warn#/Sys/Sec/Authentication#
#BC-JAS-SEC#security#C0000A7103ECA20050000508C#3935150000000004#common.com/irj#com.common.services.security.authentication.logincontext.table#USER2#0##E0E##0#Thread[HTTP
Worker [@2033389552],5,Dedicated_Application_Thread]#Plain## Logout
User: USER2 IP Address: 127.0.0.1 Authentication Stack: ticket

期望的输出

Date;Time;Type;User
2018/05/24;10:43:38:683;Login;USER1
2018/05/24;11:05:04:011;Login;USER4
2018/05/24;11:05:07:100;Logout;USER3
2018/05/24;11:07:21:314;Login;USER2

Perl

#!/usr/bin/perl

use strict;
use warnings 'all';
use feature qw(say);

my $path = "mylog.txt";
open( FILE, $path ) or die $!;

my @array;
my $i = 0;

my %csv = ( l_d => 'Date', l_t => 'Time', l_msg => 'Type', l_usr => 'User', cr => '\n', );

while ( @array = <FILE> ) {

    foreach my $line ( @array ) {

        if ( $line =~ m/^#\d.\d.#\d{4}\s\d{2}\s\d{2}\s\d{2}:\d{2}:\d{2}:\d{3}#\+\d+#\w+#\/\w+\/\w+\/Authentication/ ) {

            if ( $array[ $i + 2 ] =~ m/Login/ || $array[ $i + 2 ] =~ m/Logout/ && $array[ $i + 3 ] !~ m/NOUSER/ ) {

                my $l_d = substr( $line, 6, 10 );
                $l_d =~ s/\s/\//g;

                my $l_t   = substr( $line, 17, 12 );
                my $l_msg = substr( $array[ $i + 2 ], 0,  -1 );
                my $l_usr = substr( $array[ $i + 3 ], 6 );

                print "Date: $l_d\n";
                print "Time: $l_t\n";
                print "Type: $l_msg\n";
                print "User: $l_usr\n";

                # I would push these value into %csv('*')
                #push @{ %csv->{l_d}->[$l_d] }, $l_d;       # I would push into %csv('l_d') the $l_d value
                #push @{ %csv->{l_t}->[$l_t] }, $l_t;       # I would push into %csv('l_t') the $l_t value
                #push @{ %csv->{l_msg}->[$l_msg] }, $l_msg; # I would push into %csv('l_msg') the $l_t value
                #push @{ %csv->{l_usr}->[$l_usr] }, $ld_usr;# I would push into %csv('l_usr') the $l_t value
                # End of loop
            }
        }

        $i++;
    }
}

close( FILE );

print "Csv Example:\n\n";
print "$csv{'l_d'};$csv{'l_t'};$csv{'l_msg'};$csv{'l_usr'}\n";

#open my $filecsv, '>', 'outfile.csv' or die $!;
#$csv->print( $filecsv, \%csv );

我在放置原始日志文件时遇到了麻烦,因为我一插入它就被错误地处理了。

链接是mylog.txt文件

标签: perl

解决方案


有一些技巧可以使事情变得更简单。

  • 更改输入记录分隔符,以便一次读取整个(多行)记录。用$/.

  • 一旦你有了多行记录,就把它分成几行。您可以按行的顺序知道各种事物的位置。

  • 在处理每一行时输出结果。你不需要一个数据结构。

  • 对于更复杂的事情,请查看Text::CSV_XS以处理逗号分隔值文件的复杂性。


$/ = "\n\n";  # record separator
while( <FILE> ) {
    chomp;
    my @lines = split /\n/;
    my ($y, $m, $d, $time ) =
        $lines[0] =~ /\A\#\d+\.\#(\d+)\s+(\d+)\s+(\d+)\s+([^#]+)/;
    my $action = $lines[-2];
    my $user = (split /\s+/, $lines[-1])[-1];

    say join ';',
        "$y/$m/$d",
        $time,
        $action,
        $user
    }

但是,现在让我们回答可能将人们带到这里的名义问题。您想将数组存储为哈希值。这很容易。数组引用(实际上,所有引用)都是标量。您可以对标量执行相同的操作,包括将它们用作哈希值:

my @array = ( ... );
my %hash;

$hash{'some_key'} = \@array;  # take a reference to a named array

不过,您不需要命名数组。[ ]直接创建一个数组引用:

$hash{'some_key'} = [ ... ];  # anonymous array constructor

现在你有这个数组引用值作为你的哈希键,你想用它做数组的事情。首先,您需要取消引用它。把返回数组引用的东西放在里面@{ }

@{ $hash{'some_key'} }

在使用命名数组的任何地方使用它:

push @{ $hash{'some_key'} }, 'new value';
pop @{ $hash{'some_key'} };

Perl v5.24 具有后缀取消引用功能,这使它更漂亮:

$hash{'some_key'}->@*

使用它代替数组:

push $hash{'some_key'}->@*, 'newer value';
pop $hash{'some_key'}->@*;

推荐阅读