1use strict;
2use warnings;
3
4sub parse_log_entries {
5 my ($filename) = @_;
6 my %stats;
7 open(my $fh, '<', $filename) or die "Cannot open: $!";
8 while (my $line = <$fh>) {
9 chomp $line;
10 if ($line =~ /^(\d{4}-\d{2}-\d{2})\s+(\w+)\s+(.+)/) {
11 my ($date, $level, $message) = ($1, $2, $3);
12 $stats{$level} //= [];
13 push @{$stats{$level}}, {
14 date => $date,
15 message => $message,
16 };
17 }
18 }
19 close $fh;
20 return \%stats;
21}
22
23sub extract_fields {
24 my ($text, @patterns) = @_;
25 my %results;
26 for my $pattern (@patterns) {
27 my @matches = ($text =~ /$pattern/g);
28 $results{$pattern} = \@matches;
29 }
30 return %results;
31}
32
33sub word_frequency {
34 my ($text) = @_;
35 my %freq;
36 $text = lc $text;
37 $text =~ s/[^a-z0-9\s]//g;
38 $freq{$_}++ for split /\s+/, $text;
39 my @sorted = sort { $freq{$b} <=> $freq{$a} } keys %freq;
40 return map { [$_, $freq{$_}] } @sorted;
41}
42
43sub transform_csv {
44 my ($input, $output, $transform) = @_;
45 open(my $in, '<', $input) or die "Read error: $!";
46 open(my $out, '>', $output) or die "Write error: $!";
47 my $header = <$in>;
48 chomp $header;
49 my @fields = split /,/, $header;
50 print $out join(",", @fields) . "\n";
51 while (my $line = <$in>) {
52 chomp $line;
53 my %row;
54 @row{@fields} = split /,/, $line;
55 my %transformed = $transform->(\%row);
56 print $out join(",", @transformed{@fields}) . "\n";
57 }
58 close $in;
59 close $out;
60}