Der Regex Megathread

Begonnen von RichardCZ, 06 Mai 2020, 12:18:14

Vorheriges Thema - Nächstes Thema

RichardCZ

Zitat von: Sidey am 07 Mai 2020, 20:55:32
m/^MS;(?:P\d=-?\d+;){3,8}D=\d+;CP=\d;SP=\d;/
Eigentlich extrahieren ich alle Bestandteile dann später noch mal in einen Hash, damit ich auf die Daten zugreifen kann.
Mit named capture groups habe ich mich noch nicht so sehr versucht, wüsste aktuell auch nicht, wie man es mit mehrfach vorkommenden capture groups arbeitet :)

Gibt's ein paar Beispieldaten (so 10-20 repräsentative Zeilen gegen die gematched wird)?
Wenn ich es recht verstanen habe, matchst Du mal gegen den string als ganzes und dann nochmal gegen die "\d"'s, die dann gefangen und ausgewertet werden?
Würde vermutlich Sinn machen das gleich auf einmal zu machen.

m/^MS;(?:P\d=-?\d+;){3,8}
         D=(?<d>  \d+);
        CP=(?<cp> \d);
        SP=(?<sp> \d);/xms;


? Leider fehlt mir mehr Kontext um da qualifiziertere Aussagen treffen zu können.
Witty House Infrastructure Processor (WHIP) is a modern and
comprehensive full-stack smart home framework for the 21st century.

Wzut

#31
Ich werf nochmal meinen Hut in den Ring zum Thema MAX Telegramm prüfen & dekodieren.
So schaut jetzt meine Lösung aus :

# Beispiel  : $rmsg =  "Z0CF304420584D8120834002CF8";
# Beispiel  : $rmsg =  "Z0F0004600703780000000039003D00B9";

my $l = hex(substr($rmsg,1,2));

    if (2*$l+3 != length($rmsg))  { #+3 = +1 for 'Z' and +2 for len field in hex
Log3($name, message $rmsg len mismatch '.length($rmsg).' vs '.(2*$l+3);
        return $name;
    }

my ($len,$msgcnt,$msgFlag,$msgTypeRaw,$src,$dst,$groupid,$payload) =
$rmsg =~ m/\A Z([0-9A-F]{2}) ([0-9A-F]{2}) ([0-9A-F]{2}) ([0-9A-F]{2})
       ([0-9A-F]{6}) ([0-9A-F]{6}) ([0-9A-F]{2}) ([0-9A-F]{0,10})\z/xms;

Maintainer der Module: MAX, MPD, UbiquitiMP, UbiquitiOut, SIP, BEOK, readingsWatcher

RichardCZ

Zitat von: Wzut am 08 Mai 2020, 19:22:42
my ($len,$msgcnt,$msgFlag,$msgTypeRaw,$src,$dst,$groupid,$payload) =
$rmsg =~ m/\A Z([0-9A-F]{2}) ([0-9A-F]{2}) ([0-9A-F]{2}) ([0-9A-F]{2})
       ([0-9A-F]{6}) ([0-9A-F]{6}) ([0-9A-F]{2}) ([0-9A-F]{0,10})\z/xms;


Würde ich sagen ist ok. Die klassisch Analfixierten würden vermutlich irgendwas in der Art
my ($len,         $msgcnt,      $msgFlag,     $msgTypeRaw,
    $src,         $dst,         $groupid,     $payload)
    =  $rmsg =~ m/\A Z
    ([0-9A-F]{2}) ([0-9A-F]{2}) ([0-9A-F]{2}) ([0-9A-F]{2})
    ([0-9A-F]{6}) ([0-9A-F]{6}) ([0-9A-F]{2}) ([0-9A-F]{0,10})
    \z/xms;


machen, aber da muss man nicht zuschauen bei.  ;)
Witty House Infrastructure Processor (WHIP) is a modern and
comprehensive full-stack smart home framework for the 21st century.

Sidey

Zitat von: RichardCZ am 08 Mai 2020, 12:43:15
Gibt's ein paar Beispieldaten (so 10-20 repräsentative Zeilen gegen die gematched wird)?
Ja, ich denke es macht nicht viel her, die eine Regex zu überarbeiten.
Da gibt's es mehrere die mehr oder weniger alle an diesem Datensatz rumwerkeln mit Variationen.


Zitat von: RichardCZ link=topic=110949.msg1051655#msg1051655
Wenn ich es recht verstanen habe, matchst Du mal gegen den string als ganzes und dann nochmal gegen die "\d"'s, die dann gefangen und ausgewertet werden?
Würde vermutlich Sinn machen das gleich auf einmal zu machen.

Es gibt ein Identifier am Anfang. Im Besipiel MS, MC, MU und MN sind aber auch valide Werte. :)
Das ";" ist immer ein Trennzeichen

Nach dem Identifier finden sich Key=Value Zuordnung wieder.
P<0-7>=<Wert>
D=<Wert>
CP=<Wert>
SP=<Wert>


Gülige Werte bedienen sich aus dem Bereich [0-7]  (derzeit).

Zitat von: RichardCZ link=topic=110949.msg1051655#msg1051655
code]m/^MS;(?:P\d=-?\d+;){3,8}
         D=(?<d>  \d+);
        CP=(?<cp> \d);
        SP=(?<sp> \d);/xms;
[/code]
Für das Abgreifen von D, CP und SP ist die vorgehensweise klar.
Ich brauche noch die Werte aus Px=y wobei ich X als Key und Y als Value benötige.
Ohne named capture group könnte ich das mit $1, $2, ... abrufen.

Um jetzt mal den Umfang der Regexen zu umschreiben,
ich hab aktuell vier und alle sind ein bisschen abweichend umgesetzt. :(


m/^MS;(P\d=-?\d+;){3,8}D=\d+;CP=\d;SP=\d;
m/^MU;(P\d=-?\d+;){3,8}((CP|R)=\d+;){0,2}D=\d+;/
m/^M[cC];.*;/
m/^MN;.*;/


Je nachdem, welcher matcht wird eine dafür definierte funktion für die verarbeitung aufgerufen.

Das Auswerten der Inhalte realisiere ich aktuell via split(';') und suche in einer Schleife die passenden Werte nach dem Motto Key=Value mittlels split(/=/).

Testdaten habe ich massenweise:
https://github.com/RFD-FHEM/SIGNALduino_TOOL/blob/master/FHEM/lib/SD_Device_ProtocolList.json


MS;P1=-7949;P2=492;P3=-1978;P4=-3970;D=21232423232424242423232323232324242423232323232424;CP=2;SP=1;R=245;O;
MS;P1=492;P2=-4005;P3=-8937;P4=-2023;D=13121214121412121414121214121414141414141414141414141412141414141412121414;CP=1;SP=3;s6;e;m2;
MS;P0=-970;P1=254;P3=-1983;P4=-8045;D=14101310131010101310101010101010101010101313101010101010101313131010131013;CP=1;SP=4;
MU;P0=595;P1=344;P2=-862;P3=846;P4=244;P5=-602;P7=-251;D=1232323245454545454507074545070707450707454545070707070707074545454507074545074507454540;CP=4;R=4;
MC;LL=-409;LH=448;SL=-172;SH=262;D=238126DAA58;C=215;L=41;R=238;
MC;LL=-1002;LH=952;SL=-489;SH=475;D=000000A0EBDDC4FBFBF13EF5B6;C=486;L=104;s48;b1;
MU;P0=132;P1=500;P2=-233;P3=-598;P4=-980;P5=4526;D=012120303030303120303030453120303121212121203121212121203121212121212030303030312030312031203030303030312031203031212120303030303120303030453120303121212121203121212121203121212121212030303030312030312031203030303030312031203031212120303030;CP=0;O;
MN;D=8AA6362CC8AAAA000012F8F4;R=4;
MN;D=0405019E8700AAAAAAAA0F13AA16ACC0540AAA49C814473A2774D208AC0B0167;N=3;R=6;


Sind ein paar Varianzen enthalten :)
Signalduino, Homematic, Raspberry Pi, Mysensors, MQTT, Alexa, Docker, AlexaFhem

Maintainer von: SIGNALduino, fhem-docker, alexa-fhem-docker, fhempy-docker

RichardCZ

Zitat von: RichardCZ am 08 Mai 2020, 19:51:03
my ($len,         $msgcnt,      $msgFlag,     $msgTypeRaw,
    $src,         $dst,         $groupid,     $payload)
    =  $rmsg =~ m/\A Z
    ([0-9A-F]{2}) ([0-9A-F]{2}) ([0-9A-F]{2}) ([0-9A-F]{2})
    ([0-9A-F]{6}) ([0-9A-F]{6}) ([0-9A-F]{2}) ([0-9A-F]{0,10})
    \z/xms;


Es erreichte mich eine PM, die zeigt, dass man sich auch manchmal in die andere Richtung verlaufen kann.
Genauso wie so manch Java/Python/xxx Dev reguläre Ausdrücke meidet wie der Teufel das Weihwasser,
genauso kann es manchmal sein, dass man den Regex-Hammer zu früh herausholt - nur weil er schön
griffbereit liegt.

Eigentlich ist das nämlich ein Fall für unpack. Aufmerksam gemacht hat mich darauf @elle,
code in etwa:

if ( $rmsg !~ m{\A Z [0-9A-F]{1,30} }xms ) { # repeptition safe margin, but not "infinite"
# Log "Wrong Format", or somesuch
}

my ($len, $msgcnt, $msgFlag, $msgTypeRaw, $src, $dst, $groupid, $payload) = unpack("(A2)4(A6)2A2A10", $rmsg);


Witty House Infrastructure Processor (WHIP) is a modern and
comprehensive full-stack smart home framework for the 21st century.

Wzut

sieht auch gut aus :) mal schauen was die Praxis dazu sagt. 
Maintainer der Module: MAX, MPD, UbiquitiMP, UbiquitiOut, SIP, BEOK, readingsWatcher

Wzut

Zitat von: RichardCZ am 09 Mai 2020, 11:54:53
my ($len, $msgcnt, $msgFlag, $msgTypeRaw, $src, $dst, $groupid, $payload) = unpack("(A2)4(A6)2A2A10", $rmsg);
schaut schön aus , dekodiert aber bereits das Start Z mit und dann ist alles um ein Zeichen verschoben, dagegen
my ($len, $msgcnt, $msgFlag, $msgTypeRaw, $src, $dst, $groupid, $payload) = unpack("(A2)4(A6)2A2A10", substr($rmsg,1));
macht was es soll :)



Maintainer der Module: MAX, MPD, UbiquitiMP, UbiquitiOut, SIP, BEOK, readingsWatcher

RichardCZ

Zitat von: Wzut am 09 Mai 2020, 17:02:08
schaut schön aus , dekodiert aber bereits das Start Z mit und dann ist alles um ein Zeichen verschoben, dagegen
my ($len, $msgcnt, $msgFlag, $msgTypeRaw, $src, $dst, $groupid, $payload) = unpack("(A2)4(A6)2A2A10", substr($rmsg,1));
macht was es soll :)

Zum Beispiel.

Wobei mich ja so der Verdacht beschleicht, dass man u.U. direkt Hex werte entpacken möchte? (H bzw. h) ?

Aber wie gesagt, dieses Beispiel gehört in diesen Thread eigentlich nur herein um zu zeigen wann man Regexen nicht verwenden muss/soll.
Witty House Infrastructure Processor (WHIP) is a modern and
comprehensive full-stack smart home framework for the 21st century.

Sidey



Zitat von: Wzut am 09 Mai 2020, 17:02:08
my ($len, $msgcnt, $msgFlag, $msgTypeRaw, $src, $dst, $groupid, $payload) = unpack("(A2)4(A6)2A2A10", substr($rmsg,1));
macht was es soll :)

Sieht nett aus mit dem substr, ist vor allem einfach.
Nur so muss es nicht mehr mit Z anfangen, was aber ggf. schon an anderer Stelle geprüft wurde :)


Gesendet von meinem Moto Z (2) mit Tapatalk

Signalduino, Homematic, Raspberry Pi, Mysensors, MQTT, Alexa, Docker, AlexaFhem

Maintainer von: SIGNALduino, fhem-docker, alexa-fhem-docker, fhempy-docker

Wzut

Zitat von: Sidey am 09 Mai 2020, 18:00:11
Nur so muss es nicht mehr mit Z anfangen, was aber ggf. schon an anderer Stelle geprüft wurde :)
doch die Regel davor hat das Z ja noch drin und IMHO liefert 00_CUL je nur an 14_CUL_MAX  Parse aus wenn dessen eigener $hash->{Match} = '^Z' passt :) 
Maintainer der Module: MAX, MPD, UbiquitiMP, UbiquitiOut, SIP, BEOK, readingsWatcher