ReGaHSS: foreach [1/12 BP-1] -> Schleife ignoriert letztes leeres Element
Describe the issue you are experiencing
Wird die foreach-Anweisung mit einem tabulator-separierten string als 2. Parameter aufgerufen, dann wird das letzte Element ignoriert, falls dieses einen Leerstring enthält.
Describe the behavior you expected
Erwartet werden würde, dass die Schleife die tatsächlich bestehenden Elemente, folglich auch ein Leerstring am Ende, durchläuft. Dies hat jedoch auch zur Folge, dass eine Schleife auch bei einem komplett leeren String 1 mal durchlaufen werden würde.
Steps to reproduce the issue
Ausführung des folgenden Skriptes unter "Skript testen":
WriteLine("Start");
WriteLine(dom.BuildLabel());
WriteLine("----------------------------------------");
integer lCount = 0;
string lList = "\tA\tB\tC\tD\t\t";
string lEnum;
foreach(lEnum,lList)
{
lCount = lCount + 1;
WriteLine("'" # lEnum # "'");
}
WriteLine("Schleifenzähler: " # lCount);
WriteLine("----------------------------------------");
integer lCount = 0;
string lList = "";
string lEnum;
foreach(lEnum,lList)
{
lCount = lCount + 1;
WriteLine("'" # lEnum # "'");
}
WriteLine("Schleifenzähler: " # lCount);
WriteLine("----------------------------------------");
integer lCount = 0;
string lList = ";A;B;C;D;;";
string lEnum;
foreach(lEnum,lList.Split(";"))
{
lCount = lCount + 1;
WriteLine("'" # lEnum # "'");
}
WriteLine("ListCount: " # web.webGetValueListCount(lList));
WriteLine("Schleifenzähler: " # lCount);
WriteLine("----------------------------------------");
WriteLine("Ende");
What is the version this bug report is based on?
CCU3 mit ReGaHSS-Version R1.00.0388.0235
Which base platform are you running?
rpi3 (RaspberryPi3)
Which HomeMatic/homematicIP radio module are you using?
n/a
Anything in the logs that might be useful for us?
bestehend seit:
unbekannt (bereits mit ReGaHss-Version R1.00.0388.0102)
Additional information
Ausgabe des Skriptes:
Start
R1.00.0388.0235
----------------------------------------
''
'A'
'B'
'C'
'D'
''
Schleifenzähler: 6
----------------------------------------
Schleifenzähler: 0
----------------------------------------
''
'A'
'B'
'C'
'D'
''
ListCount: 7
Schleifenzähler: 6
----------------------------------------
Ende
Auch wenn ich das Ansinnen bzw. den Hintergrund hinter diesem Ticket/Issue verstehe, so würde ich auch hier erst gerne wieder Meinungen anderer einholen wollen. Gerade auch weil foreach ja so eine zentrale Funktion bzw. Konstrukt ist, das wir hier ggf. Gefahr laufen Dinge zu "verschlimmbessern".
Ich geb dir @BadenPower natürlich vollkommen Recht das sich hier foreach im Grunde Inkonsistent verhält wenn das letzte Element hinter einem \t der leere String ist. Auch dafür sollte es im Grunde eine letzte Iteration durchführen genauso wie es das tut wenn es nicht der leere String sondern ggf einfach ein Leerzeichen ist. Auch natürlich weil wenn der leere String in der Mitte eines via \t geteilten Arrays ist der ja entsprechend ausgegeben bzw. bearbeitet wird.
Aber wie gesagt bin ich mir nicht ganz so sicher ob man das jetzt nach all den vielen Jahren anfassen sollte, eben weil foreach ja ein sehr zentrales/wichtiges Element der Skriptsprache ist und es vielleicht zich Situation gibt wo zwar es nicht zu 100% korrekt funktioniert, aber eben so bereits seit vielen vielen Jahren. Und wenn wir das foreach nun anpassen um genau das zu reparieren (d.h. das im Falle eines leeren Strings am schluss der letzten iteration trotzdem der inhalt von foreach ausgeführt wird), dann könnten sich diese existierenden Programme / Skripte nun eben substantiell anders Verhalten oder aber eben eine letzte Iteration durchführen die vielleicht nicht kritisch ist, aber dann eben zusätzlich Zeit in Anspruch nicht was aktuell nicht der Fall ist.
Deshalb hier die Frage in die Ruhe wie hierzu die Meinungen sind.
Ich sehe hier keinen Optimierungsbedarf.
Das einzige was wir bei korrekter Funktion bekommen würden wäre doch nur ein zusätzlicher Schleifendurchlauf.
Die meisten Scripte iterieren doch über ID-Arrays von Gewerken / Kanälen usw., und da ist am Ende (soweit ich das sehe) normalerweise kein Leerstring.
Eigene Listen sind da schon "problematischer" wenn man diese mit \t (oder anderem Trenner) enden...
Hund\tKatze\tMaus\t
... aber genau hier kommt uns ja der "Bug" zugute weil eben die letzte Runde gar nicht erst gedreht wird.
Es wäre nicht nur ein zusötzlicher Schleifendurchlauf, sondern eben ein dazugehöriger Schleifendurchlauf.
Wenn ein Listenstring mit einem Trenner endet, dann wollte doch der Skriptersteller bewusst ein weiteres Element der Liste hinzufügen. Damit kommt es dem Programmierer nicht zu Gute, dass dieses Element dann einfach weggelassen wird, denn er kann nicht auf das letzte Element der Liste in der Schleife zugreifen. Bislang realisiere ich den vollständigen Zugriff auf alle Elemente mit einem Workaround,
Natürlich ist es zeitweise auch praktisch, dass der Durchlauf ignoriert wird, wenn ein Trenner am Ende steht, denn dies ermöglicht zu unterscheiden, ob eine Stringliste leer ist oder eben einen leeren (einzelnen) Wert hat, wenn der String nur ein Semikolon enthält.
Dass dies allerdings nicht so vorgesehen ist, zeigen die Ausgaben der Methoden .Enum...(), welche eine Stringliste zurückgeben, ohne dass ein Trennzeichen am Schluss vorkommt, solange kein "lleeres" Element am Schluß vorhanden ist. Nehmen wir zum Beispiel einen in der WebUI angelegten Favoriten, welcher am Schluß eine Trennzeile beinhaltet, dann wird diese Trennzeile in einer foreach-Schleife nicht berücksichtigt, wenn der 2. Parameter auf die Methode favorit.EnumNames() zurückgreift.
Ich könnte mir vorstellen, dass man die ursprüngliche Funktion beibehält und die foreach-Anweisung um einen optionalen Parameter LoopAllBlanks mit dem Defaultwert false hinzufügt und die geänderte Funktionsweise nur dann ausführt, sobald der weitere Parameter auf true gesetzt wird.
So blieben alle "alten" Skripte voll funktionsfähig und auch vollständige Iterierung wäre bei Bedarf möglich. Das Einzige was bliebe, wäre im Skript selbst zu prüfen, ob der String für den 2. Parameter ein Leerstring ist, wenn man nicht wollte, dass die Schleife 1 mal durchlaufen wird, wenn es sich um einen Leerstring handelt.