#!/usr/bin/perl use strict; use warnings; use utf8; use open qw(:std :utf8); use Excel::Writer::XLSX; my $input = 'pdfs.txt'; my $csv_out = 'anzeigen.csv'; my $xlsx_out = 'anzeigen.xlsx'; my $sep = ';'; # Hilfsfunktion: trim sub trim { my $s = shift; $s =~ s/^\s+|\s+$//g; return $s // '' } # --- Bestehende CSV einlesen (falls vorhanden) --- my %entries; if (-e $csv_out) { open(my $old, '<:encoding(UTF-8)', $csv_out) or die "Kann $csv_out nicht lesen: $!"; my $hdr = <$old>; # Kopfzeile überspringen while (<$old>) { chomp; next unless length($_); my @cols = split /$sep/, $_; # trim alle Felder @cols = map { trim($_) } @cols; my ($datum, $start, $ende, $tatort, $kennz, $marke, $file) = @cols; $entries{$file} = { Datum => $datum // '', 'Tatzeit(Anfang)' => $start // '', 'Tatzeit(Ende)' => $ende // '', Tatort => $tatort // '', Kennzeichen => $kennz // '', Marke => $marke // '', Datei => $file // '' }; } close $old; print "📂 Bestehende CSV geladen: " . scalar(keys %entries) . " Einträge\n"; } # --- Neue Daten aus pdfs.txt einlesen --- open(my $in, '<:encoding(UTF-8)', $input) or die "Kann $input nicht öffnen: $!"; while (<$in>) { chomp; next unless /:/; my ($file, $content) = split(/:/, $_, 2); $file = trim($file); $content = trim($content); # initialisieren falls neu $entries{$file} //= { Datum => '', 'Tatzeit(Anfang)' => '', 'Tatzeit(Ende)' => '', Tatort => '', Kennzeichen => '', Marke => '', Datei => $file }; # Kennzeichen if ($content =~ /Fahrzeug Kennzeichen\s+(.+)/i) { $entries{$file}->{Kennzeichen} = trim($1); next; } # Marke if ($content =~ /Marke des Fahrzeuges\s+(.+)/i) { $entries{$file}->{Marke} = trim($1); next; } # Tatort if ($content =~ /Tatort\s+(.+)/i) { $entries{$file}->{Tatort} = trim($1); next; } # Datum in der Form DD.MM.YYYY auf derselben Zeile if ($content =~ /Tattag\s*\(Datum\)\s*([0-3]?\d\.[01]?\d\.\d{4})/) { my $d = $1; if ($d =~ /(\d{2})\.(\d{2})\.(\d{4})/) { $entries{$file}->{Datum} = sprintf("%04d-%02d-%02d", $3, $2, $1); } # es könnten zusätzlich Zeiten auf dieser Zeile sein -> weiter prüfen unten } # Falls die Zeile "Tattag (Datum) (Tatzeit – Bis)" ohne Datum, wir lassen Datum unverändert (nicht überschreiben) # Zeiten: überall nach HH:MM suchen (erkennt auch "17:30- 17:49", "11:35 - 11:40 Uhr", "21:13" etc.) if ($content =~ /Tatzeit|Tatzeit|Tatzeit.*|Tattag.*Tatzeit/i or $content =~ /(\d{1,2}:\d{2})/) { my @times = ($content =~ /(\d{1,2}:\d{2})/g); # Falls Zeiten gefunden wurden, setzen (überschreiben) if (@times) { $entries{$file}->{'Tatzeit(Anfang)'} = $times[0]; $entries{$file}->{'Tatzeit(Ende)'} = $times[1] // ''; # falls keine Endzeit, leer lassen } } # Manchmal steht das Datum ohne Label (seltener), versuchen wir ein generelles Datumsmuster in content if (!$entries{$file}->{Datum} && $content =~ /(\d{2}\.\d{2}\.\d{4})/) { my $d = $1; if ($d =~ /(\d{2})\.(\d{2})\.(\d{4})/) { $entries{$file}->{Datum} = sprintf("%04d-%02d-%02d", $3, $2, $1); } } } close $in; # --- Sortieren: neueste zuerst; falls Datum leer, ans Ende --- my @sorted = sort { my $da = $entries{$a}->{Datum} // ''; my $db = $entries{$b}->{Datum} // ''; # leere Datum nach unten return $da cmp $db if $da eq '' || $db eq ''; ($db cmp $da) || ( ($entries{$b}->{'Tatzeit(Anfang)'} // '') cmp ($entries{$a}->{'Tatzeit(Anfang)'} // '') ) } keys %entries; # --- CSV schreiben (gewünschte Reihenfolge) --- open(my $csv, '>:encoding(UTF-8)', $csv_out) or die "Kann $csv_out nicht schreiben: $!"; print $csv "Datum${sep}Tatzeit(Anfang)${sep}Tatzeit(Ende)${sep}Tatort${sep}Kennzeichen${sep}Marke${sep}Datei\n"; for my $e (@sorted) { my $row = join($sep, map { $entries{$e}->{$_} // '' } qw(Datum Tatzeit(Anfang) Tatzeit(Ende) Tatort Kennzeichen Marke Datei)); print $csv "$row\n"; } close $csv; print "✅ CSV-Datei '$csv_out' erstellt.\n"; # --- XLSX erzeugen --- my $workbook = Excel::Writer::XLSX->new( $xlsx_out ); my $worksheet = $workbook->add_worksheet(); # Formatierungen my $bold_format = $workbook->add_format( bold => 1, bg_color => '#D9D9D9' ); my $date_format = $workbook->add_format( num_format => 'yyyy-mm-dd' ); my $time_format = $workbook->add_format( num_format => 'hh:mm' ); # Kopfzeile my @header = qw(Datum Tatzeit(Anfang) Tatzeit(Ende) Tatort Kennzeichen Marke Datei); $worksheet->write_row( 'A1', \@header, $bold_format ); # Datenzeilen my $row_index = 1; for my $e (@sorted) { my @row_data = ( $entries{$e}->{Datum} // '', $entries{$e}->{'Tatzeit(Anfang)'} // '', $entries{$e}->{'Tatzeit(Ende)'} // '', $entries{$e}->{Tatort} // '', $entries{$e}->{Kennzeichen} // '', $entries{$e}->{Marke} // '', $entries{$e}->{Datei} // '', ); for my $col (0..$#row_data) { my $value = $row_data[$col]; # Datum als echtes Excel-Datum (ISO + T) if ($col == 0 && $value =~ /^(\d{4})-(\d{2})-(\d{2})$/) { my $iso = sprintf("%04d-%02d-%02dT00:00:00", $1, $2, $3); $worksheet->write_date_time($row_index, $col, $iso, $date_format); } # Zeit als echte Excel-Zeit (Bruchteil eines Tages) elsif (($col == 1 || $col == 2) && $value =~ /^(\d{1,2}):(\d{2})$/) { my ($h,$m) = ($1,$2); my $time_fraction = ($h*3600 + $m*60)/86400; $worksheet->write_number($row_index, $col, $time_fraction, $time_format); } else { # Text (leer als leere Zelle) $worksheet->write_string($row_index, $col, $value // ''); } } $row_index++; } # Optional: Autofit (nur grobe Breiten setzen) $worksheet->set_column(0, 0, 12); # Datum $worksheet->set_column(1, 2, 10); # Zeiten $worksheet->set_column(3, 3, 30); # Tatort $worksheet->set_column(4, 5, 15); # Kennzeichen, Marke $worksheet->set_column(6, 6, 60); # Datei $workbook->close; print "📊 XLSX-Datei '$xlsx_out' erstellt – alle Daten sichtbar und formatiert.\n";