Array-Fehler, aber nicht bei der Syntaxprüfung und erst nach Beenden der While-Schleife

  • Hallo zusammen,

    meine Überschrift ist etwas konfus, aber ich wußte nicht, wie ich das Problem sonst beschreiben soll. Ich bin absoluter Anfänger was AutoIT angeht, hatte aber bisher den Eindruck die Scriptsprache ist leicht zu lernen, verständlich und relativ mächtig. Bis gestern.

    Ich bin dabei eine kleine Anwendung zu erstellen, die ein Verzeichnis auf Dateien mit bestimmter Endung überprüft (das funktioniert), aus dem Dateinamen einen bestimmten Teil (die Rechnungsnummer) extrahiert (das funktioniert, ist aber bisher nicht toll gelöst), diese Nummer zusammen mit dem Dateinamen in ein Array schreibt (auch das funktioniert) und die Daten aus dem Array später dann in eine Datei schreibt. Ich brauche noch einen Zwischenschritt, an dem ich bisher noch nicht gesessen habe; nämlich muss zu der Rechnungsnummer noch eine Mitgliedsnummer und ein Mitgliedsname in einer SQL-Datenbank abgefragt und ins Array integriert werden. Das ist hier allerdings jetzt zunächst mal ohne Relevanz. Danach wird mittels Programmaufruf eine Archivierung der Rechnungsdokumente unter Verwendung der Daten des Arrays $oRechArray als Verschlagwortung angestoßen (dazu dient diese index.imp-Datei).

    Ich stelle hier mal meinen Quelltext rein - wie gesagt: Ich bin Anfänger, also bitte keine Profikniffe erwarten. ;)

    Als Fehlermeldung beim Ausführen erhalte ich folgendes:

    Zitat

    C:\Austausch\AutoIT\rechnung_autoarchivierung.au3 (47) : ==> Subscript used with non-Array variable.:
    $oRechnummer = $oRechnummerArray[0]
    $oRechnummer = $oRechnummerArray^ ERROR


    Wenn ich einen Syntax-Check durchführe, erhalte ich keinen Fehler.

    Ich verstehe diese Meldung jedoch nicht. Solange das Script in der While-Schleife ist, funktioniert alles wunderbar, aber dann, wenn keine Datei mehr vorhanden ist kommt es zu diesem Fehler. Wäre nett, wenn mir jemand von euch da helfen könnte.

    Dank & Gruß

    Boni

    Einmal editiert, zuletzt von boni83 (30. Juni 2011 um 16:43)

  • Hallo Prajoss,

    danke für deine Hilfe, aber das dachte ich an der Stelle zunächst auch. Das Problem ist aber, dass bei deiner Schreibweise das Array leer ist.

    Code
    ; Die Rechnungsnummer der Datei aus dem Namen extrahieren (Ab Zeichen 10, 12 Zeichen lang)
    		$oRechnummerArray[0] = _StringBetween($oRechnungsname,$oRechNumStart,$oRechNumEnd)
    		MsgBox(0,$oRechnummerArray[0],$oRechnummerArray[0])
    		WinWaitClose($oRechnummerArray[0])


    Die Messagebox gibt mir im Betreff und im Text nichts aus. Nehme ich jetzt die [0] wieder weg, dann habe ich die Rechnungsnummer wieder im Betreff und als Text.

    Bei dieser Schreibweise funktioniert die Ausgabe in der Messagebox, aber es kommt zu einem Scripterror bei der Ausführung, der vermutlich genau die [0] haben möchte, die da fehlt:

    Code
    $oRechnummerArray = _StringBetween($oRechnungsname,$oRechNumStart,$oRechNumEnd)
    		$oRechnummer = $oRechnummerArray[0]
    		MsgBox(0,$oRechnummer,$oRechnummer)
    		WinWaitClose($oRechnummer)


    Diese Schreibweise gibt mir als Ergebnis oder Inhalt des Arrays nichts aus und lässt das Script somit in einer Endlosschleife:

    Code
    $oRechnummerArray[0] = _StringBetween($oRechnungsname,$oRechNumStart,$oRechNumEnd)
    		$oRechnummer = $oRechnummerArray[0]
    		MsgBox(0,$oRechnummer,$oRechnummer)
    		WinWaitClose($oRechnummer)

    Ich verstehe das aber an der Stelle einfach nicht. Laut Funktionsreferenz gibt _StringBetween automatisch ein Array zurück (http://translation.autoit.de/onlinehilfe/li…ringBetween.htm), aber entweder bin ich zu doof die Funktion zu nutzen oder ich verstehe wohl etwas mit den Arrays nicht richtig.

    Grüße

    Boni

  • Ok du hast recht, hätte vllt erst nachsehen sollen,

    dann bau doch einfach eine @error Abfrage rein um zu sehen ob er überhaupt etwas zurück gibt.
    Denn wenn nicht, gibts nur eine "0" und damit ist das kein Array mehr.

    [autoit]

    $oRechnummerArray = _StringBetween($oRechnungsname,$oRechNumStart,$oRechNumEnd)
    msgbox(0, "T", @error)

    [/autoit]

    Gruß

    Prajoss

    "Never touch a running System!"

  • Hm, was bezweckst du damit? Das erschließt sich mir nicht. Das "Ergebnis" müsste das selbe sein wie bei meinem Test mit der Messagebox. Bei Schreibweise

    Code
    $oRechnummerArray[0] = _StringBetween(oRechnungsname,$oRechNumStart,$oRechNumEnd)
    MsgBox(0,$oRechnummerArray[0],$oRechnummerArray[0])


    ist die Ausgabe in der Messagebox leer (kein Betreff, kein Text). Bei meiner ursprünglichen Schreibweise

    Code
    $oRechnummerArray = _StringBetween(oRechnungsname,$oRechNumStart,$oRechNumEnd)
    MsgBox(0,$oRechnummerArray[0],$oRechnummerArray[0])


    bekomme ich die korrekte Rechnungsnummer ausgegeben, aber ich erhalte nach Ende der While-Schleife eine Fehlermeldung.

    Ich bin inzwischen dabei das Ganze umzustricken, da die While-Schleife an der Stelle äußerst ungünstig ist. Trotzdem würde mich interessieren wo jetzt der Fehler ist. Laut Beschreibung von _StringBetween gibt diese Funktion ein Array als Ergebnis zurück.

    Grüße

    Boni

  • Das Problem an deiner Messagebox ist, dass wenn gar kein Array zurückgegeben wird,
    versucht er trotzdem $oRechnummerArray[0] darzustellen und wenn das kein Array ist, bam crash.

    "Never touch a running System!"

  • Man könnte, um Fehler zu vermeiden, das ganze bedingt auszuführen, also nach _StringBetween() eine If-Abfrage durchzuführen

    Etwa so:

    [autoit]

    $oRechnummerArray[0] = _StringBetween()
    If IsArray($oRechnummerArray) Then
    .
    .
    .
    Endif

    [/autoit]

    Edit: Fehler korrigiert

    UNPLEASANT SPOILER

    You just lost the game!

    Einmal editiert, zuletzt von shadow667 (30. Juni 2011 um 15:05)

  • Aber wenn dann

    [autoit]

    IsArray($oRechnummerArray)

    [/autoit]

    Gruß

    Selbstverständlich! :D
    Sowas kommt dabei raus, wenn 3 kleine Kinder um einen rumhüpfen und man nur eben mal helfen möcht...

    UNPLEASANT SPOILER

    You just lost the game!

  • Der Fehler ist schon viel weiter oben. So wie ich das sehe verlässt du die Schleife niemals, es ist eine Endlosschleife die irgendwann abstürzt, nämlich dann wenn keine weitere Datei mehr zufinden ist.
    Hier mal ein überarbeitetes Script mit Kommentaren:

    Spoiler anzeigen
    [autoit]


    #include<string.au3>
    #include <array.au3>

    [/autoit] [autoit][/autoit] [autoit]

    ; Variablendeklaration
    $oVSHDir = @ScriptDir & "\" ; ACHTUNG: Pfad zum testen geändert...
    $oRechSuchString = "Rechnung_*.pdf"
    $oRechNumStart = "Rechnung_"
    $oRechNumEnd = "#"
    $oIndeximp = $oVSHDir & "index.imp"
    $i = 0 ; zahlen gibt man nicht als string an...
    dim $oRechArray[500][2] ; sehr problematisch, denn du weisst garnicht sicher ob nicht vielleicht mehr als 500 Dateien im Ordner sind schau dir am besten redim an um die Arraygröße dynamisch zu erweitern

    [/autoit] [autoit][/autoit] [autoit]

    ;while FileExists($oVSHDir & $oRechSuchString) ; sinnlose Abbruchbedingung, da immer eine datei mit dem Schema Rechnung_*.pdf existieren wird ausser du löschst/verschiebst die Dateien in der Schleife

    [/autoit] [autoit][/autoit] [autoit]

    if FileExists($oVSHDir & $oRechSuchString) Then
    $oFirstFile = FileFindFirstFile($oVSHDir & $oRechSuchString)
    if $oFirstFile = -1 Then
    MsgBox(0,"Mahatma Fatal Error","Das Verzeichnis enthaelt keine Dateien")
    Exit
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    while $oFirstFile <> -1 ; abruchbedingung ist fehlerhaft, oFirstFile wird niemals -1 werden
    MsgBox(0,"",$oFirstFile) ; Beweis, dass ofirstfile nie -1 wird
    $oFile = FileFindNextFile($oFirstFile)
    if @error then ExitLoop ; wenn ein Fehler auftritt, also keine weitere Datei gefunden wird, dann verlassen wir die Schleife.
    $oRechnungsname = FileGetLongName($oFile)

    [/autoit] [autoit][/autoit] [autoit]

    $oRechnummerArray = _StringBetween($oRechnungsname,$oRechNumStart,$oRechNumEnd) ; scheiterte immer dann wenn keine Datei mehr zufinden war, das sollte nun nicht mehr passieren, beweis, wenn du die @error zeile auskommentierst
    $oRechnummer = $oRechnummerArray[0]

    [/autoit] [autoit][/autoit] [autoit]

    while StringLeft($oRechnummer,1) = 0
    $oRechnummer = StringReplace($oRechnummer,"0","",1)
    WEnd
    ; hier könnte noch ein redim stehen um das Array größer zumachen wenn kein Platz mehr ist, also mehr als 500 Dateien...
    $oRechArray[$i][0] = $oRechnummer
    $oRechArray[$i][1] = $oRechnungsname

    [/autoit] [autoit][/autoit] [autoit]

    $i = $i + 1 ; warum hier die 1 als String angeben? habs mal geändert
    WEnd
    Else
    MsgBox(0,"Fehler","Keine Rechnungsdokumente im Ordner gefunden.")
    EndIf
    ;WEnd ;... die ganze äussere Schleife ist unfug und sollte durch eine if bedingung ersetzt werden.

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    _ArrayDisplay($oRechArray) ; zur Kontrolle

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ; das hier hab ich zum testeb auskommentiert...

    [/autoit] [autoit][/autoit] [autoit]

    ;~ $oFH = FileOpen($oIndeximp,1)

    [/autoit] [autoit][/autoit] [autoit]

    ;~ while $i >= 0
    ;~ FileWriteLine($oFH,"^Daten1^,^Daten2^,^^,^^,^"& $oRechArray[$i][0] &"^,^^,^^,^^,^KK^,^^,^^,^^,^^,^^,^^,^^,^^,^^,^^,"& $oRechArray[$i][1])
    ;~ $i = $i - 1 ; hier auch als string.... geändert
    ;~ WEnd

    [/autoit] [autoit][/autoit] [autoit]

    ;~ FileClose($oFH)

    [/autoit]
  • Hmm, irgendwie verstehe ich das jetzt grade nicht. Ich bekomme als Ergebnis eine 0 - somit wäre das Ergebnis von _StringBetween($oRechnungsname,$oRechNumStart,$oRechNumEnd) kein Array. Aber laut Funktionsreferenz muss es ein Array sein und wenn ich auf Variablenschreibweise umstelle, dann bekomme ich nichts als Ergebnis. Der Fehler muss also doch irgendwo anders liegen. Es kann doch nicht sein, dass ich ein Ergebnis mit $oRechnummerArray[0] bekomme, welches <> 0 ist, aber eigentlich etwas in eine Variable $oRechnummerArray reinschreibe was aber wiederum bei Verlassen der Schleife in der diese Deklaration stattfindet zu einem Fehler führt, oder? Helft mir bitte das zu verstehen, denn ich resigniere gerade (und darf das eigentlich nicht, weil mir noch die Hälfte bis zur Fertigstellung fehlt).

    Dank & lieben Gruß

    Boni

  • Du könntest zum einen eine Dateiliste mit _FileListToArray() erstellen

    Frage: wie genau sehen eigentlich die Dateinamen aus?

    UNPLEASANT SPOILER

    You just lost the game!

  • Wo bekommst du eine 0 ? Redest du nun von meinem überarbeiteten Script? Denk dran ich hab den Pfad oben geändert, das musst du natürlich noch anpassen.

    EDIT:
      @Shadow ja so hätte ich das auch gemacht ;)

  • Sorry für den Doppelpost, da war misterspeed schneller. Ich gehe mal kurz auf deine Einwürfe ein:
    $i = 0 ; zahlen gibt man nicht als string an...
    --> War mir nicht bewusst, da habe ich wieder was gelernt. ;)
    dim $oRechArray[500][2] ; sehr problematisch, denn du weisst garnicht sicher ob nicht vielleicht mehr als 500 Dateien im Ordner sind schau dir am besten redim an um die Arraygröße dynamisch zu erweitern
    --> In dem Fall schon, denn es werden nie mehr als 100 Dokumente erstellt und die werden dann am Schluss nach der Archivierung gelöscht. War aber noch zur Ausbesserung vorgesehen, um in anderen Geschäftsstellen Fehler auszuschließen.
    ;while FileExists($oVSHDir & $oRechSuchString) ; sinnlose Abbruchbedingung, da immer eine datei mit dem Schema Rechnung_*.pdf existieren wird ausser du löschst/verschiebst die Dateien in der Schleife
    --> Danke, das hatte ich schon auf IF/Else geändert. Ich poste im Anhang noch mal meinen aktuellen Versuch (der soweit auch klappt, nur eben ohne _StringBetween)
    while $oFirstFile <> -1 ; abruchbedingung ist fehlerhaft, oFirstFile wird niemals -1 werden
    --> Das hatte ich inzwischen auch schon rausgefunden und entsprechend geändert.
    $oRechnummerArray = _StringBetween($oRechnungsname,$oRechNumStart,$oRechNumEnd) ; scheiterte immer dann wenn keine Datei mehr zufinden war, das sollte nun nicht mehr passieren, beweis, wenn du die @error zeile auskommentierst
    --> Das erklärt mir den Fehler bzw. das Auftreten des Fehlers. Dieser kam nämlich bisher immer nur dann, wenn die While-Schleife alle bestehenden Dateien durchlaufen hatte.
    ; hier könnte noch ein redim stehen um das Array größer zumachen wenn kein Platz mehr ist, also mehr als 500 Dateien...
    $oRechArray[$i][0] = $oRechnummer
    --> Damit befasse ich mich dann später noch. Möchte das eigentlich auch so variabel wie möglich gestalten, da es in anderen Umgebungen (in anderen Geschäftsstellen mit mehr Rechnungen bspw.) sonst zu Problemen kommen könnte.
    $i = $i + 1 ; warum hier die 1 als String angeben? habs mal geändert
    --> Ich kenne PHP ein wenig, war aber noch nicht in Versuchung gekommen zu testen, ob $i++ auch funktioniert. Die Angabe als String weil ich nicht wusste, dass ich Zahlen auch einfach so angeben kann.

    Danke vielmals, damit ist mir nämlich inzwischen klar, warum es nicht funktioniert hat; zumal ich auch die array.au3 nicht mit ins Boot genommen habe.

    Hier der aktuelle Stand (um weiter zu kommen, hatte ich auf StringTrimLeft/Right umgestellt):

    Damit kann die eigentliche Anfrage als Gelöst abgeschlossen werden. :thumbup:
    Statt einem Fehler waren es mehrere (wenngleich wohl nur einer zur Fehlermeldung geführt hat). Naja, Schleifen und ich werden einfach keine Freunde mehr; die Arrays und ich arbeiten noch dran. :wacko:

    Vielen lieben Dank für eure Hilfe.

    Boni

    Edit:
    misterspeed
    Nein, meine Antwort war noch auf deinen Vorgänger gemünzt. Du hattest deine Hilfe abgeschickt als ich meine Antwort grade geschrieben habe. ;)

  • Warum ich nach dem Dateinamen frage:

    [autoit]

    $oRechNumStart = "Rechnung_"
    $oRechNumEnd = "#"
    .
    .
    .
    .
    .
    $oRechnummerArray = _StringBetween($oRechnungsname,$oRechNumStart,$oRechNumEnd)

    [/autoit]

    Demnach müssten die Dateinamen ja so aussehen:
    Rechnung_1#.pdf
    Rechnung_2#.pdf

    UNPLEASANT SPOILER

    You just lost the game!

  • Ja, so ähnlich: Rechnung_000001100624#000000658652.PDF
    Ich habe keine Ahnung, was die Nummer nach der Raute ist. Wahrscheinlich nur eine laufende Nummer die aus der Anwendung heraus vergeben wird, denn sonst wäre mir nichts bekannt, was mit dieser Anzahl an Stellen Sinn ergeben würde.

    Falls Interesse besteht, dann stelle ich das "Programm" nach Fertigstellung noch mal hier rein. Werde da wohl noch so einige Funktionen vergewaltigen müssen, bis alles so klappt wie es soll. Für mich als Programmierunerfahrenen Netzwerk-/Serveradmin (vor Jahren mal PHP-Kleinkramschubser, aber nie wirklich umfangreichere Sachen programmiert - mein schwierigstes "Programm" war ein Kalender) ist das wie für einen Liliputaner eine 1 Meter hohe Bar: Eigentlich unerreichbar und nur mit massiver Hilfe oder Hilfsmitteln nutzbar. Nein, ich wollte damit keine Liliputaner diskriminieren, mir fiehl nur grade kein dümmeres Beispiel ein. :S

    misterspeed
    Ok, dann verstehe ich den Fehler jetzt komplett. Das lag also wirklich nur daran, dass die Schleife auch ohne Dateinamen nicht beendet wurde und die Funktion mit einem NULL-Wert offenbar nicht klar kommt.

  • Hi,
    auch wenn das Problem gelöst ist:
    Wenn du in AutoIt so etwas wie '$i++' suchst, kannst du eine 'ähnliche# Konstruktion benutzen:

    [autoit]

    $i+=1

    [/autoit]

    oder wieviel auch immer du addieren möchtest ;)
    Es bleibt deinem Forscherdrang überlassen, herauszufinden ob und wie es mit -*/ etc. geht ^^
    Gruß
    ytwinky

    (Ich) benutze stets die aktuelle (Beta) und SciTE..

  • Dein Problem lag in erster Linie daran, dass du die Schleife nicht verlassen hast wenn keine Datei mehr gefunden wurde. Das Ergebn für den Dateinamen war dann ein leerer String, welcher von stringbetween dann natürlich als ergebnislos weiterverarbeitet wurde. Da stringbetween nix gefunden hat und somit auch kein Array zurückgegeben hat ist das Script dann abgestürzt sobald du die variable als Array angesprochen hast. Stringbetween hatte kein Array geliefert also darf man die Variable auch nicht mit Array index ansprechen.

    Zu deiner Frage wie man in autoit Variablen in kurzform erhöht:

    [autoit]


    $i = $i + 1
    ; ist identisch mit
    $i+=1
    ; Ausserdem gibt es noch -= , *= , /= und &= (für Stringverkettung)

    [/autoit]

    EDIT: Da war ytwinky schneller

    Einmal editiert, zuletzt von misterspeed (30. Juni 2011 um 17:03)

  • Wenn alle Rechnungen in einem Ordner sind, bin ich immernoch der Meinung, daß du mit _FileListToArray() am besten bedient wärst.
    Damit erhältst du ein Array, welches die Anzahl der gefundenen Files ($Array[0]) sowie alle Dateien ($Array[1] bis $Array[n]) beinhaltet.
    Dieses kannst du dann ganz einfach in ner For... Next Schleife abarbeiten.

    Etwa so:

    [autoit]

    #include <File.au3>
    #include <Array.au3>

    [/autoit][autoit][/autoit][autoit]

    $FileList = _FileListToArray("C:\DeinPfad\","Rechnung_*.pdf",1) ;1 Gibt nur Dateien zurück
    If IsArray($FileList) Then _ArrayDisplay($FileList) ;Hier kannst du dir die Liste der gefundenen Dateien ansehen
    For $I = 1 To $FileList[0]
    $Nummer = _StringBetween($FileList[$I], "Rechnung_", "#")
    .
    .
    Next

    [/autoit]
    UNPLEASANT SPOILER

    You just lost the game!

    Einmal editiert, zuletzt von shadow667 (30. Juni 2011 um 17:09)