Autor Thema: split(/\|/, $hash->{REGEXP}) ist semantisch falsch  (Gelesen 657 mal)

Offline ska-

  • New Member
  • *
  • Beiträge: 12
split(/\|/, $hash->{REGEXP}) ist semantisch falsch
« am: 08 Mai 2021, 22:04:01 »
Hallo,

in notify.pm (und anderen, wie dem FileLog) kann man per addRegexpPart and removeRegexpPart Teile der mit | verketteten regex hinzufügen oder entfernen. Ausserdem wird die regex stets als /^$re$/ verwendet, weshalb im Wiki die Klammerung empfohlen wird: https://wiki.fhem.de/wiki/Notify#Einfache_ODER_Funktion . add/remove nutzt intern einen HASH, womit die Reihenfolge durcheinander geraten kann.

Problem 1) regex Device:brightness:.*(\d|1[0-4])
wird am | zerlegt, add/remove parts teilt an dieser Stelle, wenn nun die Reihenfolge geändert wird, ist die regex zerstört.

Problem 2) regex a|b|c|0
wird intern zu: ^a|b|0$
d.h. (nur) a ist am Anfang, b  nirgend und (nur) 0 am Ende gebunden.

Deshalb soll man laut Wiki
Problem 3) (a|b|c|0)
schreiben, was (bei mir im Test) nach remove "c" zu: (a|0)|b
wurde.


Folgender Code stellt sicher, dass immer nur an korrekten | geteilt wird. Leider wird in Problem 3 dann immer nur ein Part angezeigt.
BTW: IMHO sollte die regex statt als /^$re$/ mit /^(?:$re)$/ getestet werden, dann braucht man die Klammerung im Befehl nicht.

diff --git a/FHEM/91_notify.pm b/FHEM/91_notify.pm
index ca6bc22..9946c5b 100644
--- a/FHEM/91_notify.pm
+++ b/FHEM/91_notify.pm
@@ -171,6 +171,27 @@ notify_Attr(@)
 
 ###################################
 
+# Split RE into OR'ed parts
+sub re_split ($) {
+    my @re;
+    my @h = grep { length($_) > 0 } split(/\|/, $_[0]);
+    my $re = shift @h;
+    while(@h) {
+       eval { 'Hallo' =~ m/^($re)$/; };
+       if($@) {        # $re is not a valid regex
+               my $h = shift @h;
+               $re .= '|' . $h;
+       } else {
+               push @re, $re;
+               $re = shift @h;
+       }
+    }
+    push @re, $re;
+    return @re;
+}
+
+###################################
+
 sub
 notify_Set($@)
 {
@@ -189,28 +210,26 @@ notify_Set($@)
   return "$cmd needs $sets{$cmd} parameter(s)" if(@a-$sets{$cmd} != 2);
 
   if($cmd eq "addRegexpPart") {
-    my %h;
     my $re = "$a[2]:$a[3]";
-    map { $h{$_} = 1 } split(/\|/, $hash->{REGEXP});
-    $h{$re} = 1;
-    $re = join("|", sort keys %h);
     return "Bad regexp: starting with *" if($re =~ m/^\*/);
-    eval { "Hallo" =~ m/^$re$/ };
+    eval { 'Hallo' =~ /^(?:$re)/; };
     return "Bad regexp: $@" if($@);
+    my @h = re_split($hash->{REGEXP});
+    push @h, $re unless grep { $_ eq $re } @h;
+    $re = join("|", @h);
     $hash->{REGEXP} = $re;
     $hash->{DEF} = "$re ".$hash->{".COMMAND"};
     notifyRegexpChanged($hash, $re);
     
   } elsif($cmd eq "removeRegexpPart") {
-    my %h;
-    map { $h{$_} = 1 } split(/\|/, $hash->{REGEXP});
-    return "Cannot remove regexp part: not found" if(!$h{$a[2]});
-    return "Cannot remove last regexp part" if(int(keys(%h)) == 1);
-    delete $h{$a[2]};
-    my $re = join("|", sort keys %h);
-    return "Bad regexp: starting with *" if($re =~ m/^\*/);
-    eval { "Hallo" =~ m/^$re$/ };
-    return "Bad regexp: $@" if($@);
+    my @h = re_split($hash->{REGEXP});
+    return "Cannot remove last regexp part" if(scalar(@h) == 1);
+    my @re = grep { $_ ne $a[2] } @h;
+    return "Cannot remove regexp part: not found" if scalar(@h) == scalar(@re);
+    my $re = join("|", @re);
+    return "Bad regexp: starting with *" if($re =~ m/^\*/);    # should not necessary
+    eval { "Hallo" =~ m/^$re$/ };      # should not necessary
+    return "Bad regexp: $@" if($@);    # should not necessary
     $hash->{REGEXP} = $re;
     $hash->{DEF} = "$re ".$hash->{".COMMAND"};
     notifyRegexpChanged($hash, $re);
@@ -249,7 +268,7 @@ notify_fhemwebFn($$$$)
   my $ret .= "<div class='makeTable wide'><span>Change wizard</span>".
              "<table class='block wide'>";
   my $row = 0;
-  my @ra = split(/\|/, $hash->{REGEXP});
+  my @ra = re_split($hash->{REGEXP});
   $ret .= "<tr class='".(($row++&1)?"odd":"even").
         "'><td colspan='2'>Change the condition:</td></tr>";
   if(@ra > 1) {

Ich denke, dieser Patch bindet jede regex ans Anfang / Ende:
diff --git a/FHEM/91_notify.pm b/FHEM/91_notify.pm
index 59f29a4..e2651b2 100644
--- a/FHEM/91_notify.pm
+++ b/FHEM/91_notify.pm
@@ -99,15 +99,15 @@ notify_Exec($$)
   for (my $i = 0; $i < $max; $i++) {
     my $s = $events->[$i];
     $s = "" if(!defined($s));
-    my $found = ($n =~ m/^$re$/ || "$n:$s" =~ m/^$re$/s);
+    my $found = ($n =~ m/^(?:$re)$/ || "$n:$s" =~ m/^(?:$re)$/s);
     if(!$found && AttrVal($n, "eventMap", undef)) {
       my @res = ReplaceEventMap($n, [$n,$s], 0);
       shift @res;
       $s = join(" ", @res);
-      $found = ("$n:$s" =~ m/^$re$/);
+      $found = ("$n:$s" =~ m/^(?:$re)$/);
     }
     if($found) {
-      next if($iRe && ($n =~ m/^$iRe$/ || "$n:$s" =~ m/^$iRe$/));
+      next if($iRe && ($n =~ m/^(?:$iRe)$/ || "$n:$s" =~ m/^(?:$iRe)$/));
       Log3 $ln, 5, "Triggering $ln";
       my %specials= (
                 "%NAME" => $n,
« Letzte Änderung: 08 Mai 2021, 22:27:21 von ska- »

 

decade-submarginal