Frage zu vergleichende Operatoren

  • Hallo,

    ich habe eine Frage zu vergleichende Operatoren.

    Ich habe ein Array mit folgenden Werten :

    $array[0] = ""
    $array[1] = 0
    $array[2] = 1

    Normalerweise würde ich jetzt so prüfen, ob das jeweilge Element leer ist :
    For $i = 0 to 2
    If $array[$i] = "" Then ....
    Next

    Mit dieser Abfrage bekomme ich nicht nur Element 0, sondern auch Element 1, obwohl die Null doch nicht "leer" ist ? Wird die 0 eventuell als NUL interpretiert ?
    Wenn ich die Abfrage in
    If $array[$i] == "" Then ....
    ändere, funktioniert meine Theorie.

    Wieso ist das so ? Ich stelle die Frage, weil ich ca. 3 Stunden in meinem Script nach dem Fehler gesucht habe und ich jetzt den Sinn dahinter verstehen will, um den Fehler nicht zu wiederholen.

    Ich würde mich freuen, wenn mir das jemand erklären kann.


    Viele Grüße
    Sven

  • AutoIt nimmt für jede Variable den Typ string, deshalb kann es zu Problemen bei "" und 0 führen.

    Wo hast du das denn her?
    Hier ensteht das Problem eben weil gerade eben kein Stringvergleich durchgeführt wird sondern die Daten beide als Integer behandelt werden.

    Heißt das, das 0 als NUL interpretiert wird ?

    Nein - die 0 bleibt wie sie ist.
    Der Leerstring wird implizit zu 0.
    Warum? - weil du Äpfel mit Birnen vergleichst:

    Du vergleichst einen String ("") mit einer Integerzahl (0).
    Wenn man unterschiedliche Datentypen miteinander vergleicht muss erst eines der beiden in den jeweiligen anderen konvertiert werden, denn nur gleiche Datentypen können verglichen werden.
    Im Fall eines Floats und eines Integers wird z.b. vor dem Vergleich der Integer in eine Float-Zahl konvertiert.
    Will man nun so etwas skurriles machen wie du - nämlich einen String mit einer Zahl zu vergleichen wird deine Abfrage implizit zu 0 = "".
    Hierzu wird der zweite Operand ("") vor dem Vergleich noch in den Datentyp des ersten Operanden (0) konvertiert. Un da Int("") nunmal 0 ergibt bleibt schlussendlich als Vergleich stehen: 0 = 0.

    Im zweiten Teil umgehst du das "Problem" in dem du statt dem =-Operator den ==-Operator verwendest. Dieser Operator erzwingt einen Stringvergleich (und zwar case sensitive). Das heißt alle Operanden werden vorher in einen String konvertiert bevor sie verglichen werden.
    Also deinem Beispiel wird implizit aus 0 == "" ein String(0) = String(""). Und da 0 in einen String konvertiert "0" ergibt, wird dein Vergleich implizit zu "0" = "" - und wird folglich False zurückgeben.

    Um dein Problem zu lösen solltest du dir Gedanken machen wie es überhaupt dazu kommt, dass du unterschiedliche Datentypen vergleichst.

    • Offizieller Beitrag

    Hallo,

    nur noch mal für @alpines ;) , der Datentyp in dem alles gespeichert wird der heißt Variant. Der heißt so, weil er unterschiedliche Datentypen aufnehmen kann, wie das folgende Beipiel zeigt.

    AutoIt
    Local $array[] = [ "String", 0xFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 12.45, Binary("test"), Ptr(0x12341234) ]
    
    
    For $i = 0 to UBound($array) -1
    	ConsoleWrite("Type of $array[" & $i & "] = " & VarGetType($array[$i]) & @CRLF)
    Next

    Das macht es auf der einen Seite einfach, da man sich keine Gedanken darüber machen muss welche Daten in den Variablen gespeichert werden. Auf der anderen Seite ist man aber auch selbst verantwortlich die richtigen Operationen mit den Daten durchzuführen.

  • Das einfachste wäre hier vielleicht, auf einen Vergleichsoperator zu verzichten und einfach IsNumber zu verwenden. Der Rest wurde ja schon geklärt.

  • Was möchtest du mit IsNumber klären?
    crap_inhuman möchte herausfinden ob eine Variable leer ist - wenn sie also nur deklariert aber nicht definiert wurde.
    Neue Variablen werden in AutoIt implizit als Leerstring definiert.
    Wenn du nun IsNumber() zur Klärung dieser Frage einsetzen willst dann verstehe ich nicht wie das damit funktionieren soll.
    IsNumber liefert ja nur True zurück bei Double/Int32/Int64-Variablen.
    Darauf Rückschlüsse auf einen String zu ziehen geht nicht da AutoIt ja weiterhin noch die Typen Reference(Pointer)/HWND/Bool/Binary und Array kennt.
    Wenn eine, von ihm zu prüfende Variable einen entsprechenden Typ besitzt, wird sie ihm fälschlicherweise als "leer" angezeigt.

    Einmal editiert, zuletzt von AspirinJunkie (4. Juni 2015 um 12:16)

    • Offizieller Beitrag

    Alternativ kannst du ja dafür sorgen, dass Variablen niemals undefinierte Inhalte haben. Erstelle sie einfach mit Inhalt Null, dann kannst du mit einer eigenen Funktion auf _IsNull prüfen.

    Spoiler anzeigen
  • @Aspirin Im Beispielarray waren aber sonst nur Zahlen, daher geht das hier auch. Sobald ein Element leer ist, wird IsNumber false zurückgeben. Ist es wie im Beispiel (mit einer Nummer) gefüllt, dann eben true.

  • Moin!

    Hier mein Vorschlag zum Thema:

    Ist semantisch wahrscheinlich nicht ganz ok, aber so klappts auf jeden Fall...

  • crap_inhuman hat diesen Fall ja schon implizit mit dem ==-Operator umgesetzt. Damit spart man sich das explizite String().
    Mal abgesehen, davon dass Binary('') damit auch als Leerstring erkannt wird obwohl es keiner ist.
    In AutoIt sind, wie gesagt, Variablen, wenn sie deklariert aber nicht definiert werden, implizit ein Leerstring.
    Um das abzufragen muss man also auch den Variablentyp mit reinnehmen: If IsString($Var) And ($Var = "") Then 

  • BugFix .
    Für den Fall, dass ein Array mehr wie 3 "Zeilen" hat, was ist bitte die schnellste Art es mit '0' zu füllen?
    Eine Schleife? Oder gibt es da etwas trickreicheres?

    Danke
    Peter

    Hinweise auf Suchmaschinen finde ich überflüssig - wer fragt hat es nicht gefunden oder nicht verstanden. Die Antwort gibt sich oftmals schneller als der Hinweis auf Dr. Goggle & Co.

    Ab 19-10-22 ergänzt um:

    Die Welt wird nicht bedroht von den Menschen, die böse sind, sondern von denen, die das Böse zulassen. (Frei nach Albert Einstein)

    • Offizieller Beitrag

    was ist bitte die schnellste Art es mit '0' zu füllen?

    Für numerisch '0' kannst du es imho nur in der Schleife sinnvoll lösen.
    Falls du mit einem Stringausdruck vorbelegen möchtest, kannst du auch mit StringSplit arbeiten. Aber denk dran: wie der Name sagt ist es eine Stringoperation, d.h. selbst wenn du einen String mit Nullen splittest, enthält das Array keine numerischen Werte, sondern nur den String '0'.

    AutoIt
    ; Array mit 60 Elementen erstellen, vorbefüllen mit '0'
    $s0 = '000000000000000000000000000000000000000000000000000000000000' ; 60*'0'
    Global $aNull = StringSplit($s0, '', 2)
    ConsoleWrite('Ist Inhalt numerisch? - ' & (IsNumber($aNull[0]) = 1) & @CRLF)

    Zuweisungsoperationen für ein Array in einer Schleife sind aber auch nichts zeitkritisches. Das arbeitet AutoIt in ms ab. Insofern braucht man sich da nicht noch verrenken um eine Alternative zu finden. ^^

  • Kommt auch bisschen auf den Anwendungsfall an.
    Wenn du nichts macht, ist die Vorbelegung wie gesagt ein Nullstring.
    wenn du dann damit rechnest wird dieser implizit als numerisch 0 betrachtet - also genau das was du eigentlich wolltest.