# file KLEIDER/web/src/sitestyle/Placeholders.pm # Platzhalter in Zeichenketten ersetzen # 2020-04-08 Herbert Schiemann # GPL Version 2 oder neuer package Herbaer::Placeholders ; BEGIN { use Exporter; use POSIX qw (strftime); our $VERSION = 20200408; our @ISA = qw (Exporter); our @EXPORT = qw (subst_placeholders reset_counter); our @EXPORT_OK = qw (subst_placeholders_expl); our $_digs = { "alnum" => "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", "ALNUM" => "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", "alpha" => "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", "ALPHA" => "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", }; # Formate für zeitbezogene Platzhalter our $_tm_fmt = { "ts" => "%Y%m%d%H%M%S", "ds" => "%Y%m%d", "time" => "%Y-%m-%dT%H:%M:%S", "tm" => "%H:%M:%S", "date" => "%Y-%m-%d", "month" => "%Y-%m", "year" => "%Y", "datum" => "%d.%m.%Y", "zeit" => "%H:%M", }; } my $_nxt_n = {}; # Ergibt die Funktion, die den nächsten Zähler eines Typs liefert sub _nxt_f { my $t = shift; my $ln = 1; my $b = 10; my $c = 1; # Übertrag-Start my $v; my $d; if ( $t =~ /^dec(\d+)/ ) { $d = \$_digs -> {"alnum"}; $b = 10; $ln = $1 + 0; $v = substr ($$d, 0, 1) x $ln ; } elsif ( $t =~ /^dec/ ) { $d = \$_digs -> {"alnum"}; $b = 10; $v = substr ($$d, 0, 1); } elsif ( $t =~ /^hex(\d+)/ ) { $d = \$_digs -> {"alnum"}; $b = 16; $ln = $1 + 0; $v = substr ($$d, 0, 1) x $ln ; } elsif ( $t =~ /^hex/ ) { $d = \$_digs -> {"alnum"}; $b = 16; $v = substr ($$d, 0, 1); } elsif ( $t =~ /^HEX(\d+)/ ) { $d = \$_digs -> {"ALNUM"}; $b = 16; $ln = $1 + 0; $v = substr ($$d, 0, 1) x $ln ; } elsif ( $t =~ /^HEX/ ) { $d = \$_digs -> {"ALNUM"}; $b = 16; $v = substr ($$d, 0, 1); } elsif ( $t =~ /^alpha(\d+)/ ) { $d = \$_digs -> {"alpha"}; $b = 26; $ln = $1 + 0; $c = 0; } elsif ( $t =~ /^alpha/ ) { $d = \$_digs -> {"alpha"}; $b = 26; $c = 0; } elsif ( $t =~ /^ALPHA(\d+)/ ) { $d = \$_digs -> {"ALPHA"}; $b = 26; $ln = $1 + 0; $c = 0; } elsif ( $t =~ /^ALPHA/ ) { $d = \$_digs -> {"ALPHA"}; $b = 26; $c = 0; } elsif ( $t =~ /^n(\d+)_(\d+)/ ) { $d = \$_digs -> {"alnum"}; $b = $1 + 0; $ln = $2 + 0; } elsif ( $t =~ /^n(\d+)/ ) { $d = \$_digs -> {"alnum"}; $b = $1 + 0; } elsif ( $t =~ /^N(\d+)_(\d+)/ ) { $d = \$_digs -> {"ALNUM"}; $b = $1 + 0; $ln = $2 + 0; } elsif ( $t =~ /^N(\d+)/ ) { $d = \$_digs -> {"ALNUM"}; $b = $1 + 0; } elsif ( $t =~ /^a(\d+)_(\d+)/ ) { $d = \$_digs -> {"alpha"}; $b = $1 + 0; $ln = $2 + 0; $c = 0; } elsif ( $t =~ /^a(\d+)/ ) { $d = \$_digs -> {"alpha"}; $b = $1 + 0; $c = 0; } elsif ( $t =~ /^A(\d+)_(\d+)/ ) { $d = \$_digs -> {"ALPHA"}; $b = $1 + 0; $ln = $2 + 0; $c = 0; } elsif ( $t =~ /^A(\d+)/ ) { $d = \$_digs -> {"ALPHA"}; $b = $1 + 0; $c = 0; } else { # Ausweich-Fall: dezimaler Zähler $d = \$_digs -> {"alnum"}; $b = 10; $v = substr ($$d, 0, 1); } $b = length ($$d) if $b < 2 || $b > length ($$d); sub { my $i; my $n; if (! defined ($v) ) { return $v = substr ($$d, 0, 1) x $ln ; } for ($i = length ($v); $i--;) { $n = index ($$d, substr ($v, $i, 1)) + 1; if ($n < $b) { substr ($v, $i, 1, substr ($$d, $n, 1)); return $v; } substr ($v, $i, 1, substr ($$d, 0, 1)); } $v = substr ($$d, $c, 1) . $v; }; } # _nxt_f # liefert den nächsten Wert sub _nxt_v { my $k = shift; ( $_nxt_n -> {$k} //= _nxt_f ($k) ) -> (); } # "intern" von subst_placeholders verwendet sub _sp { my ($t, $k, $v) = @_; $t //= ''; $t eq '#' ? _nxt_v ($k) : $t eq 't#' && defined ($_tm_fmt -> {$k}) ? strftime ($_tm_fmt -> {$k}, localtime()) : defined ($v -> {$k}) ? $v -> {$k} : "\$\{$k\}" ; } # füllt Platzhalter sub subst_placeholders { my ($str, $vals) = @_; $vals //= {}; if (!$str) {} elsif (ref $str eq "HASH") { my ($k, $v); while ( ($k, $v) = each %$str ) { $str -> {$k} = subst_placeholders ($v, $vals); } } elsif (ref $str eq "ARRAY") { my $v; foreach $v (@$str) { $v = subst_placeholders ($v, $vals); } } elsif (ref $str eq "SCALAR") { $$str = subst_placeholders ($$str, $vals); } elsif (ref $str eq "CODE") {} else { $str =~ s/\$\{([a-z]*#)?([a-zA-Z0-9_]+)\}/_sp($1, $2, $vals)/ge ; } $str; } # setzt einen Zähler zurück sub reset_counter { my $k = shift; $_nxt_n -> {$k} = undef; } # "intern" von subst_placeholders_expl verwendet sub _sp_expl { my ($k, $v) = @_; defined ($v -> {$k}) ? $v -> {$k} : "\$\{$k\}" } # füllt nur Platzhalter, die explizit in $vals angegeben sind sub subst_placeholders_expl { my ($str, $vals) = @_; $vals //= {}; if (!$str) {} elsif (ref $str eq "HASH") { my ($k, $v); while ( ($k, $v) = each %$str ) { $str -> {$k} = subst_placeholders_expl ($v, $vals); } } elsif (ref $str eq "ARRAY") { my $v; foreach $v (@$str) { $v = subst_placeholders_expl ($v, $vals); } } elsif (ref $str eq "CODE") {} else { $str =~ s/\$\{([a-zA-Z0-9_]+)\}/_sp_expl($1, $vals)/ge ; } $str; } 1; # end of file KLEIDER/web/src/sitestyle/Placeholders.pm