Moin!
Bei der Verwendung der Methode 'parseParams' ist aufgefallen, dass diese (zumindest aus meiner Sicht) nicht korrekt mit Parametern umgeht, die zwar wie "Key=Value"-Paare aussehen, jedoch durch Anführungszeichen geschützt (und dadurch eingentlich Einzelparameter) sind. Sie werden gnadenlos mitzerlegt (s. u. Parameter "a4=x").
fhem> {Dumper(parseParams('a1 a2 a3 b1=x b2=x b3="a=x" "a4=x"'))}
$VAR1 = [
'a1',
'a2',
'a3'
];
$VAR2 = {
'b1' => 'x',
'b3' => 'a=x',
'b2' => 'x',
'"a4' => 'x"'
};
Im Anhang ist ein einfaches Patch, das diese Situation behebt:
fhem> {Dumper(parseParams('a1 a2 a3 b1=x b2=x b3="a=x" "a4=x"'))}
$VAR1 = [
'a1',
'a2',
'a3',
'a4=x'
];
$VAR2 = {
'b2' => 'x',
'b3' => 'a=x',
'b1' => 'x'
};
Bitte um Prüfung ung ggf. übernahme.
Grüße
Alexander
Und wenn wir schon dabei sind, hätte ich noch einen Wunsch... :)
Mir ist aufgefallen, dass die Methode 'parseParams' in MQTT-Modul reinkopiert wurde (dort ist auch der oben beschriebene Fehler festgestellt worden), mit der Änderung, dass Zeichen ':' anstatt '=' als 'key=Value'-Trenner verwendet wird. Halte ich für unschön und schlage vor die Methode in fhem.pl um einen optionalen Parameter zu erweitern, der eine Redefinition dieses Trenners erlaubt (natürlich mit einem Defaultwert gleich '=').
fhem> {Dumper(parseParams('a1 a2 a3 b1=x b2=x b3="a=x" "a4=x"',undef,undef,':'))}
$VAR1 = [
'a1',
'a2',
'a3',
'b1=x',
'b2=x',
'b3="a=x"',
'a4=x'
];
$VAR2 = {};
Ich würde dem Modul-Maintainer anschliessend auch gern einen 'Bereinigungspatch' schicken.
Patch anbei :)
Find ich gut. Es gibt aber eine (kleine) Unstimmigkeit. Die man vielleicht gleich glatt ziehen kann/sollte.
Der Patch ignoriert, wie unmittelbar davor bei der Perl-Klammererkennung, die führenden Leerzeichen.
# the key can not start with a { -> it must be a perl expression # vim:}
} elsif( $key =~ m/^\s*{/ ) { # for vim: }
$value = $param;
$key = undef;
}
+ # the key can not start with a ' or "
+ elsif ( $key =~ m/^\s*('|")/ ) {
Im Anschluss bei der Entfernung der Anführungszeichen und Zusammensetzung von $value werden keine führenden Anführungszeichen mehr ignoriert.
#collect all parts until the closing ' or "
while( $param && $value =~ m/^('|")/ && $value !~ m/$1$/ ) {
my $next = shift(@params);
last if( !defined($next) );
$value .= $joiner . $next;
}
#remove matching ' or " from the start and end
if( $value =~ m/^('|")/ && $value =~ m/$1$/ ) {
$value =~ s/^.(.*).$/$1/;
}
Leerzeichen können übrigens an dieser Stelle nur auftreten wenn $seperator kein Leerzeichen ist.
a1=a:a2=b:"a3=c": "a4=d": "a5=e:f:g"
Folge:
a4 wird (neu) als Wertepaar ignoriert aber die Anführungszeichen bleiben wie bisher.
"a5=e, f und g" wandern in den Array. Vorher wurde "a5=e gehasht. f und g" wanderten in den Array
Lösungsansatz:
1. Bei deiner Anführungszeichenerkennung wird \s* raus genommen, dann ist es Einheitlich inkompatibel zu umgebenden Leerzeichen. Macht es aber bei a4 und a5 nicht besser.
2. Man fügt dem anschließenden Code s.o. 6x "\s*" hinzu. Dann werden Leerzeichen bei Anführungszeichen so wie bei { } ignoriert.
#collect all parts until the closing ' or "
while( $param && $value =~ m/^\s*('|")/ && $value !~ m/$1\s*$/ ) {
my $next = shift(@params);
last if( !defined($next) );
$value .= $joiner . $next;
}
#remove matching ' or " from the start and end
if( $value =~ m/^\s*('|")/ && $value =~ m/$1\s*$/ ) {
$value =~ s/^\s*.(.*).\s*$/$1/;
}
3. Man ignoriert die umgebenen Leerzeichen schon bei dem split am Anfang. Dann kann zusätzlich in der Perl-Klammererkennung das \s* raus, was den ganzen Code etwas leichter verständlich macht.
Die Frage ist dann nur, ob irgendwo umgebende Leerzeichen im Attribut gewünscht sind!?
my @params;
if( ref($cmd) eq 'ARRAY' ) {
@params = @{$cmd};
} else {
- @params = split($separator, $cmd);
+ @params = split(/\s*$separator\s*/, $cmd);
#oder
#+ @params = split($separator, trim($cmd));
}
Gruß
Ich verstehe noch nicht, warum die urspruengliche Zerlegung des gezeigten Beispiels ein Problem ist, und Phills fix macht mir Angst :)
Den zweiten Patch finde ich aber sinnvoll, ich habe es kurz getestet und eingecheckt.
Zitat von: rudolfkoenig am 28 Februar 2018, 22:11:19
Ich verstehe noch nicht, warum die urspruengliche Zerlegung des gezeigten Beispiels ein Problem ist, und Phills fix macht mir Angst :)
Weil ein Paar in der Form: "a4 => x" entsteht. Also mit dem Schlüssel "a4 und Wert x"
Und es leider nicht möglich ist a4=x als eine einzelne ganze Zeichenkette zu bekommen.
Ansonsten schützen ja die Anführungszeichen die damit umschlossenen Parameter vor der Zerlegung.
Außerdem ist sonst die Zerlegung auch nicht konsequent, fügt man ein Leerzeich vor dem Trenner, verhält sich die Funktion anders, als wenn der String ein Leerzeichen nach dem Trenner enthält.
fhem> {Dumper(parseParams('"asd=asdasd"'))}
$VAR1 = [];
$VAR2 = {
'"asd' => 'asdasd"'
};
fhem> {Dumper(parseParams('"as d=asdasd"'))}
$VAR1 = [
'as d=asdasd'
];
$VAR2 = {};
fhem> {Dumper(parseParams('"asd=as dasd"'))}
$VAR1 = [
'dasd"'
];
$VAR2 = {
'"asd' => 'as'
};
P.S. Phills Idee habe ich (glaube ich) verstanden und finde sie sinnig. Den Code muss ich mir aber auch noch mal zu Gemüte führen :)
ZitatWeil ein Paar in der Form: "a4 => x" entsteht. Also mit dem Schlüssel "a4 und Wert x"
Na das habe ich schon kapiert, aber wieso besteht man auf sowas?
Wenn man parseParams aufruft, dann geht man doch von key=value Syntax aus.
Naja, die Funktion liefert ja getrennt die Paare und die Enzelwerte. Die letzteren aus meiner Sicht nicht konsequent, da nicht jeder Wert möglich.
Aufgefallen ist das im Kontext des MQTT-Moduls, auch wenn der Syntax dort nachträglich wohl mit etwas 'Gewalt' reingepresst wurde.
Auch bei Paarzerlegung gibt es wahrscheinlich ein Problem: ein Key-Wert mit dem '='-Zeichen dürfte auch nicht möglich sein.