(gelöst) Regex Experte gesucht :-)

Begonnen von Haecksler, 09 Februar 2016, 12:45:34

Vorheriges Thema - Nächstes Thema

Haecksler

Hallo zusammen,
ich bin so ziemlich am verzweifeln, habe gestern versucht aus einem Reading mit mehreren Daten, einzelne UserReadings per Regex zu generieren.
Das komische daran ist, das es bei 2 Werten funktioniert und bei 2 nicht.

Hier das Reading aus dem die einzelnen Werte extrahiert werden sollen (Stammt aus eine 1-Wire OWCOUNT device):
day D08 Gas: 7.08 m^3 GasM: 50.96 m^3 Strom: 6.70 kWh StromM: 43.94 kWh

Hier die Funktionen mit dem Regex-Teil:
sub Gas_Tag_F () {((ReadingsVal("Energie_Zaehler","day","")) =~ /.*Gas:\s([-\.\d]+).*/);return return $1;}
sub Gas_Tag_Monat_F () {((ReadingsVal("Energie_Zaehler","day","")) =~ /.*GasM:\s([-\.\d]+).*/);return $1;}
sub Strom_Tag_F () {((ReadingsVal("Energie_Zaehler","day","")) =~ /.*Strom:\s([-\.\d]+).*/);return $1}
sub Strom_Tag_Monat_F () {((ReadingsVal("Energie_Zaehler","day","")) =~ /.*StromM:\s([-\.\d]+).*/);return $1;}


Komisch ist, dass ich für die Werte "GasM" und "StromM" die korrekten Werte bekomme, für "Gas" und "Strom" wird jedoch "get" zurückgegeben.
Kann das jemand nachvollziehen? Bin absolut ratlos :-[.

Gruß,
Stefan

Hans Franz

Hast du evtl. noch eine vergessene sub mit identischen Namen?

Gruß
Hans
Raspi
CUL, Nano-CUL
FHT8V, FHT80B, S300TH
WM1000WZ, ELRO
LW12, LD382,DS18B20

Haecksler

Zitat von: Hans Franz am 09 Februar 2016, 13:27:00
Hast du evtl. noch eine vergessene sub mit identischen Namen?

Gruß
Hans
Nein, habe die sub auch erst gemacht nach dem ich mir das komische Verhalten nicht erklären konnte.
Davor hatte ich alles direkt im UserReading stehen ohne sub, aber mit dem gleichen Ergebnis.

turo

Oder sind es 2 Leerzeichen bei Gas/StromM: ? (Sieht zwar in dem Beispiel nicht so aus, aber das kann ja auch bei cut-and-paste "optimiert" worden sein)

Gruss,
turo
3xRaspberry PI, Homematic, SELVE Rollos, 1-wire, Logitech Harmony, Alexa, Fussbodenheizung (ESP8266), Netatmo

Haecksler

Zitat von: turo am 09 Februar 2016, 13:44:23
Oder sind es 2 Leerzeichen bei Gas/StromM: ? (Sieht zwar in dem Beispiel nicht so aus, aber das kann ja auch bei cut-and-paste "optimiert" worden sein)

Gruss,
turo
Schon alles getestet...habe gestern 3h alles mögliche probiert :'(

darkness

Hey,

habe mich mit regex in FHEM noch nicht so auseinander gesetzt. Aber in der ersten Zeile gibt es zwei return hintereinander. Soll das so sein?
Dritte Zeile fehlt ein Semikolon.

Gruß

Haecksler

Zitat von: darkness am 09 Februar 2016, 14:06:46
Hey,

habe mich mit regex in FHEM noch nicht so auseinander gesetzt. Aber in der ersten Zeile gibt es zwei return hintereinander. Soll das so sein?
Dritte Zeile fehlt ein Semikolon.

Gruß
Nein sollte nicht so sein, ist aber C&P Fehler und nicht wirklich so, also in Tat und Wahrheit steht da nur 1 return.  ::)

Haecksler

Habe eine Lösung gefunden, aber immer noch keine Ahnung wieso es oben nicht funktioniert.


sub Gas_Tag_F () {((ReadingsVal("Energie_Zaehler","day","")) =~ /\s([\d]+\.[\d]+).*\s([\d]+\.[\d]+).*\s([\d]+.[\d]+).*\s([\d]+.[\d]+).*/);return $1;}
sub Gas_Tag_Monat_F () {((ReadingsVal("Energie_Zaehler","day","")) =~ /.*GasM:\s([-\.\d]+).*/);return $1;}
sub Strom_Tag_F () {((ReadingsVal("Energie_Zaehler","day","")) =~ /\s([\d]+\.[\d]+).*\s([\d]+\.[\d]+).*\s([\d]+.[\d]+).*\s([\d]+.[\d]+).*/);return $3}
sub Strom_Tag_Monat_F () {((ReadingsVal("Energie_Zaehler","day","")) =~ /.*StromM:\s([-\.\d]+).*/);return $1;}


8)

Markus Bloch

Das Problem liegt hierbei in dem ".*" was hinter dem jeweiligen Wert folgt:

Inhalt: "Gas: 7.08 m^3 GasM: 50.96 m^3 Strom: 6.70 kWh StromM: 43.94 kWh"

sub Gas_Tag_F () {ReadingsVal("Energie_Zaehler","day","") =~ /Gas:\s*([-\.\d]+)/; return $1;}
sub Gas_Tag_Monat_F () {ReadingsVal("Energie_Zaehler","day","") =~ /GasM:\s*([-\.\d]+)/; return $1;}
sub Strom_Tag_F () {ReadingsVal("Energie_Zaehler","day","") =~ /Strom:\s*([-\.\d]+)/; return $1;}
sub Strom_Tag_Monat_F () {ReadingsVal("Energie_Zaehler","day","") =~ /StromM:\s*([-\.\d]+)/; return $1;}


Am besten einen Regulären Ausdruck immer so kurz wie möglich bauen.

Gruß
Markus
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

Haecksler

Zitat von: Markus Bloch am 09 Februar 2016, 18:23:59
Das Problem liegt hierbei in dem ".*" was hinter dem jeweiligen Wert folgt:

Inhalt: "Gas: 7.08 m^3 GasM: 50.96 m^3 Strom: 6.70 kWh StromM: 43.94 kWh"

sub Gas_Tag_F () {ReadingsVal("Energie_Zaehler","day","") =~ /Gas:\s*([-\.\d]+)/; return $1;}
sub Gas_Tag_Monat_F () {ReadingsVal("Energie_Zaehler","day","") =~ /GasM:\s*([-\.\d]+)/; return $1;}
sub Strom_Tag_F () {ReadingsVal("Energie_Zaehler","day","") =~ /Strom:\s*([-\.\d]+)/; return $1;}
sub Strom_Tag_Monat_F () {ReadingsVal("Energie_Zaehler","day","") =~ /StromM:\s*([-\.\d]+)/; return $1;}


Am besten einen Regulären Ausdruck immer so kurz wie möglich bauen.

Gruß
Markus
Danke! Man lernt ja nie aus.

turo

@Markus:
Ich habe noch mal nachgegrübelt und ich verstehe immer noch nicht, was da abläuft. Kannst Du vielleicht kurz erklären, warum das .* in dem Fall schädlich ist? (Du hast ja auch dem \s ein "*" verpasst, was meine "2 Leerzeichen-Hypothese" stützt, aber die hatte ja Haecksler schon verworfen.)

Ich scheitere übrigens schon daran, das erste Posting direkt in Perl nachzuvollziehen:
perl -e '"Gas: 7.08 m^3 GasM: 50.96 m^3 Strom: 6.70 kWh StromM: 43.94 kWh" =~ /.*Gas:\s([-\.\d]+).*/; print $1;'
gibt bei mir perfekt 7.08. Alles sehr mysteriös.

Gruss,
turo
3xRaspberry PI, Homematic, SELVE Rollos, 1-wire, Logitech Harmony, Alexa, Fussbodenheizung (ESP8266), Netatmo

JoWiemann

Jörg Wiemann

Slave: RPi B+ mit 512 MB, COC (868 MHz), CUL V3 (433.92MHz SlowRF); FHEMduino, Aktuelles FHEM

Master: CubieTruck; Debian; Aktuelles FHEM

turo

Danke für den Hinweis auf die Doku, aber ich behaupte mal, dass ich den Unterschied zwischen "greedy", "non-greedy" und "posessive" kenne. Das hilft mir nur nicht weiter dabei, zu verstehen, warum Haeckslers erstes Beispiel _nicht_ matched (und nachvollziehen kann ich es ja auch nicht). Das erste ".*" ist natürlich greedy und wird erst mal versuchen, den ganzen String zu matchen. Aber das muss es ja beim Backtracking wieder aufgeben (es ist ja nicht posessive) , weil das "Gas:" an genau einer Stelle matchen kann. Das "+" ist wiederum auch greedy, so dass es sich die ganze Zahl krallt und dann ist es auch vollkommen egal, ob da noch ein ".*" dahinter kommt.

(OK, der "\" vor dem . in den [] muss da nicht sein, aber das funktioniert auch mit. Effizienter ist der Match natürlich ohne ".*", weil die Regex Engine dann nicht so viel backtracken muss.)

Also im Moment habe ich 3 Erklärungsmöglichkeiten:
1. Ich stehe heute total auf dem Schlauch und kann keine Regexps mehr.
2. Haecksler hat uns belogen ;-) und das Beispiel ist nicht korrekt gepostet (Noch ein paar Leerzeichen, unprintable chars, vielleicht ein Tab)
3. Magie oder ein sonst bisher unerklärter Effekt (so wie eine weitere Deklaration an anderer Stelle)

Keine von den 3 Möglichkeiten gefällt mir und ich entschuldige mich gleich bei Haecksler, dass ich 2. in der Liste habe, aber "so was ist schon mal vorgekommen" (meistens unabsichtlich).

Grübelnder Gruss,
turo
3xRaspberry PI, Homematic, SELVE Rollos, 1-wire, Logitech Harmony, Alexa, Fussbodenheizung (ESP8266), Netatmo

stromer-12

Zitat von: turo am 10 Februar 2016, 13:57:22
(OK, der "\" vor dem . in den [] muss da nicht sein, aber das funktioniert auch mit.

Der "\" vor dem Punkt bedeutet, das der Punkt ein Punkt ist und kein beliebiges Zeichen.
FHEM (SVN) auf RPi1B mit HMser | ESPLink
FHEM (SVN) virtuell mit HMLAN | HMUSB | CUL

turo

@stromer-12:
Ne, in echt?

Der . ist nicht special in character classes und braucht an der Stelle deshalb auch nicht escaped werden. (Siehe "Camel Book", 4th ed., p. 204 ganz oben).

Da müsst Ihr Euch schon ein bisschen mehr anstrengen mit der Erklärung! ;-)

Gruss,
turo
3xRaspberry PI, Homematic, SELVE Rollos, 1-wire, Logitech Harmony, Alexa, Fussbodenheizung (ESP8266), Netatmo