# ----------------------------------------------------------------------------- =encoding utf8 =head1 NAME Quiq::Record - Verarbeitung von Text-Records =head1 BASE CLASS L =head1 DESCRIPTION Ein Text-Record ist eine Folge von Schlüssel/Wert-Paaren in Textform, wobei =over 2 =item * ein Schlüssel eine Folge von alphanumerischen Zeichen oder Unterstrich ('_') oder Bindestrich ('-') ist, und =item * ein Wert ein beliebiger einzeiliger oder mehrzeiliger Text ist. =back Stringrepräsentation: Schlüssel1: Wert1 Schlüssel2: Wert2 ... oder Schlüssel1: Wert1 Schlüssel2: Wert2 ... oder ein Mischung aus beidem oder @@Schlüssel@@ Wert1 @@Schlüsse2@@ Wert2 Um die dritte Repräsentation (mit @@Schlüssel@@) zu erzeugen, muss als Option -format => '@' angegeben werden. =cut # ----------------------------------------------------------------------------- package Quiq::Record; use base qw/Quiq::Object/; use v5.10; use strict; use warnings; our $VERSION = '1.197'; use Quiq::String; use Quiq::Option; use Quiq::Path; # ----------------------------------------------------------------------------- =head1 METHODS =head2 Klassenmethoden =head3 fromString() - Lies Schlüssel/Wert-Paare aus String =head4 Synopsis @keyVal | $keyValA = $class->fromString($str); @keyVal | $keyValA = $class->fromString(\$str); =head4 Description Lies Text-Record aus Zeichenkette $str, zerlege ihn in Schlüssel/Wert-Paare und liefere die Liste der Schlüssel/Wert-Paare zurück. Im Skalarkontext liefere eine Referenz auf die Liste. =over 2 =item * NEWLINEs am Anfang und am Ende eines Werts werden entfernt. =item * Eine Einrückung innerhalb eines mehrzeiligen Werts wird entfernt. Eine Einrückung ist die längste Folge von Leerzeichen oder Tabs, die allen Zeilen eines mehrzeiligen Werts gemeinsam ist. =back =cut # ----------------------------------------------------------------------------- sub fromString { my $class = shift; # @_: $str -or- \$str my $ref; if (!defined $_[0]) { # undef $ref = \''; } elsif (ref $_[0]) { # String-Ref $ref = $_[0]; } else { $ref = \$_[0]; # String } my (@keys,@vals); if (substr($$ref,0,1) eq '@') { @keys = $$ref =~ /^\@\@([\w-]+)\@\@ */gm; @vals = split /^\@\@[\w-]+\@\@ */m,$$ref; } elsif (substr($$ref,0,1) eq '=') { @keys = $$ref =~ /^==([\w-]+)== */gm; @vals = split /^==[\w-]+== */m,$$ref; } else { @keys = $$ref =~ /^([\w-]+) *[:=] */gm; @vals = split /^[\w-]+ *[:=] */m,$$ref; } shift @vals; my @arr; $#arr = @keys*2-1; for (my $i = 0; $i < @keys; $i++) { $arr[$i*2] = $keys[$i]; my $val = Quiq::String->removeIndentation($vals[$i]); $arr[$i*2+1] = $val; } return wantarray? @arr: \@arr; } # ----------------------------------------------------------------------------- =head3 fromFile() - Lies Schlüssel/Wert-Paare aus Datei =head4 Synopsis @keyVal | $keyValA = $class->fromFile($file,@opt); =head4 Arguments =over 4 =item $file Datei, die den Record enthält. =back =head4 Options =over 4 =item -encoding => $encoding Character Encoding, z.B. 'UTF-8'. =back =head4 Description Wie L, nur dass der Record aus Datei $file gelesen wird. =cut # ----------------------------------------------------------------------------- sub fromFile { my ($class,$file) = splice @_,0,2; # @_: @opt # Optionen my $encoding = undef; Quiq::Option->extract(\@_, -encoding => \$encoding, ); return $class->fromString(Quiq::Path->read($file,-decode=>$encoding)); } # ----------------------------------------------------------------------------- =head3 toString() - Schreibe Schlüssel/Wert-Paare auf String =head4 Synopsis $str = $class->toString(@keyVal,@opt); $str = $class->toString(\@keyVal,@opt); =head4 Options =over 4 =item --format => ':'|'@' (Default: ':') Im Falle von ':' erzeuge das Format: : Im Falle von '@' erzeuge das Format: @@@@ =item -indent => $n (Default: 4) Tiefe der Einrückung. =item -ignoreNull => $bool (Default: 0) Ignoriere Schlüssel/Wert-Paare, bei denen der Wert null ist. =item -space => $n (Default: 0) Anzahl Leerzeilen zwischen den Einträgen. =item -strip => $bool (Default: 1) Entferne Leerzeilen am Anfang und Whitespace am Ende des Werts. =back =head4 Description Generiere für die Schlüssel/Wert-Paare @keyVal eine Text-Record Repräsentation und liefere diese zurück. =cut # ----------------------------------------------------------------------------- sub toString { my $class = shift; my $arr = ref $_[0]? shift: \@_; # @_: Argumente my $format = ':'; my $indent = 4; my $ignoreNull = 0; my $space = 0; my $strip = 1; Quiq::Option->extract(\@_, -format => \$format, -indent => \$indent, -ignoreNull => \$ignoreNull, -space => \$space, -strip => \$strip, ); $indent = ' ' x $indent; $space = "\n" x $space; my $str = ''; for (my $i = 0; $i < @$arr; $i += 2) { my $key = $arr->[$i]; my $val = $arr->[$i+1]; if (!defined $val) { $val = ''; } if ($strip) { $val =~ s/^\n+//; $val =~ s/\s+$//; } if ($val eq '' && $ignoreNull) { next; } if ($format eq ':' && $indent) { Quiq::String->indent(\$val,$indent); } if ($space && $str) { $str .= $space; } if ($format eq ':') { $str .= sprintf "%s:\n%s\n",$key,$val; } else { $str .= sprintf "\@\@%s\@\@\n%s\n",$key,$val; } } return $str; } # ----------------------------------------------------------------------------- =head3 toFile() - Schreibe Schlüssel/Wert-Paare auf Datei =head4 Synopsis $class->toFile($file,@keyVal,@opt); $class->toFile($file,\@keyVal,@opt); =head4 Options Siehe L =head4 Description Wie L, nur dass der Record auf eine Datei geschrieben wird. Die Methode liefert keinen Wert zurück. =cut # ----------------------------------------------------------------------------- sub toFile { my $class = shift; my $file = shift; # @_: siehe toString() Quiq::Path->write($file,$class->toString(@_)); return; } # ----------------------------------------------------------------------------- =head1 VERSION 1.197 =head1 AUTHOR Frank Seitz, L =head1 COPYRIGHT Copyright (C) 2021 Frank Seitz =head1 LICENSE This code is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut # ----------------------------------------------------------------------------- 1; # eof