frankx: PHP CLI unter Win

Hellihello

weiß jemand, welche Dateien aus dem Win-PHP-zip-Package (http://www.php.net/downloads.php) nötig sind, um PHP-CLI.exe laufen zu lassen? Sozusagen die Minimal benötigten Dateien?  Dazu ist es vermutlich nötig zu wissen, welche Funktionen man benutzen möchte, oder?

Im Wesentlichen überlege ich, mit

  
$excel_app = new COM("Excel.application") or Die ("Did not connect");  

eine Excelliste auszulesen und das Ergebnis (Array/Objekt) dann per FTP zu kopieren. Das FTP schafft ja cmd/batch auch selbst.

Ich dachte es wäre fein, dann einer der Anwenderinnen die Minimalkonfiguration in einem Ordner zu übermitteln, darin nur das Script, die Batchdatei, die Exceldatei sowie die nötigen PHP-Dateien.

Dank und Gruß,

frankx

  1. Hallo,

    für die vorgestellte Aufgabe würde ich PHP nur dann nutzen, wenn man mich
    dazu prügelte.

    Im Wesentlichen überlege ich, mit

    $excel_app = new COM("Excel.application") or Die ("Did not connect");

    
    > eine Excelliste auszulesen und das Ergebnis (Array/Objekt) dann per FTP zu kopieren. Das FTP schafft ja cmd/batch auch selbst.  
      
    dafür würde ich den Windows Scripting Host mit JScript/VB-Script oder  
    gleich Excel-VBA nutzen.  
      
    
    > Ich dachte es wäre fein, dann einer der Anwenderinnen die Minimalkonfiguration in einem Ordner zu übermitteln, darin nur das Script, die Batchdatei, die Exceldatei sowie die nötigen PHP-Dateien.  
      
    dann braucht man den Anwenderinnen nichts zu geben als ein Knöpfchen oder eine Verknüpfung.  
      
      
    Freundliche Grüße  
      
    Vinzenz
    
    1. Hellihello Vinzenz,

      dafür würde ich den Windows Scripting Host mit JScript/VB-Script oder
      gleich Excel-VBA nutzen.

      Ja, da war ich auch schonmal dran vorbeigekommen. Die Befehle sind ja im Grund auch ident. Ich hatte nun eben damit mal gespielt, weil der Excel_Spreadsheet_Reader bei einer aktuellen Tabelle nicht wirklich zuverlässig funktionierte. Nach einer (!) Änderung in einer Zelle, konnte er plötzlich nichts mehr lesen. Schad, denn das könnte man ja dann auf dem Server laufen lassen. Anwenderin lädt Excelliste hoch und schwupp, alles fertig.

      Mit VBA hatte ich auch schon mal was probiert. Da sah das dann so aus:

        
      Sub SaveCSV1()  
      Dim Bereich         As Object  
      Dim Zeile           As Object  
      Dim Zelle           As Object  
      Dim strTemp         As String  
      Dim Pfad            As String  
      'Const Pfad          As String = "c:\"  
      Const Dateiname     As String = "Produktliste_delimited_meine"  
      Const Extension     As String = ".CSV"  
      Const Trennzeichen  As String = "###"  
      Const Kapselzeichen As String = """"  
        
         Pfad = ActiveWorkbook.Path & "\" 'aktueller Pfad des Dokumentes zzgl Backslash  
        
          ' weiss nicht, wie sub aufrufen  
          UnixSekunden = DateDiff("s", CDate(#1/1/1970#), Now)  
          Dim Quelldatei, Zieldatei As String  
          Quelldatei = Pfad & Dateiname & Extension     ' Namen der Quelldatei festlegen.  
          Zieldatei = Pfad & Dateiname & "-" & UnixSekunden & Extension  ' Namen der Zieldatei festlegen.  
          DateiDa = Dir(Quelldatei)  
          If DateiDa > "" Then  
          FileCopy Quelldatei, Zieldatei    ' Quell- in Zieldatei kopieren.  
          Else  
          End If  
          ' ende kopieren  
        
         'Hier kann auch ein eigener Range angegeben werden  
         Set Bereich = ActiveSheet.UsedRange  
        
         ' Dateihandle #1 öffnen, siehe weiter unten: schreiben, schließen  
         Open Pfad & Dateiname & Extension For Output As #1  
        
         For Each Zeile In Bereich.Rows  
            For Each Zelle In Zeile.Cells  
               If InStr(1, Zelle.Text, Trennzeichen) > 0 Then   'angepasst T.Ramel  
                  'Zellen, die ein Trennzeichen beinhalten in Kapselzeichen setzen  
                  strTemp = strTemp & Kapselzeichen & CStr(Zelle.Text) & _  
                            Kapselzeichen & Trennzeichen  
               Else  
                  strTemp = strTemp & CStr(Zelle.Text) & Trennzeichen  
               End If  
            Next  
            strTemp = Left(strTemp, Len(strTemp) - 3) & "***"    'angepasst T.Ramel und R sauer  
            Print #1, strTemp  
            strTemp = ""  
         Next  
         Close #1  
         ' Bereich wieder freigeben (Ressourcen schonen)  
         Set Bereich = Nothing  
      End Sub  
        
      Function FileThere(FileName As String) As Boolean  
           FileThere = (Dir(FileName) > "")  
      End Function  
      
      

      Ein eigenes wasserdichtes "C"SV sozusagen. Ich hatte damals auch so grundsätzlich gedacht: willst aus Excel (Propiretär) raus, musste VBA (proprietär) nehmen.

      Mein Problem, so meine ich mich jetzt - nicht nochmal getestet - zu erinnern war, dass Zellen nach ca. 1000 Zeichen abgeschnitten werden.  Das hatte ich vorhin auch mal angedacht, das nochmal zu testen und dann entsprechend zu posten, wie diese 1000-Zeichen-Beschränkung aufgehoben werden kann.

      Das macht Excel übrigens auch, wenn man per C# und ODBC zugreift. Da hilft dann aber, in den ersten 8 Zeilen in der entsprechenden Spalte dann langen Text zu platzieren.

      dann braucht man den Anwenderinnen nichts zu geben als ein Knöpfchen oder eine Verknüpfung.

      Ja, das hatte ich mal in Word gemacht: Ein Smiley in der Menüzeile, und das Makro scnhurrte los.

      Dank und Gruß,

      frankx

      1. Hellihello nochmal:

        Mein Problem, so meine ich mich jetzt - nicht nochmal getestet - zu erinnern war, dass Zellen nach ca. 1000 Zeichen abgeschnitten werden.  Das hatte ich vorhin auch mal angedacht, das nochmal zu testen und dann entsprechend zu posten, wie diese 1000-Zeichen-Beschränkung aufgehoben werden kann.

        Genau, vielleicht ist ja auch was im Code falsch?

        mit

          
         $excel_app2 = new COM("Excel.application") or Die ("Did not connect");  
         $Workbook2 = $excel_app->Workbooks->Open('D:\xampp\htdocs\Excelreader_Sammlung\vba\Produktliste_zum_Testen_mit_allem_mit_vba.xls') or Die('Did not open filename');  
          $Worksheet2 = $Workbook2->Worksheets('Tabelle2');  
         var_dump($Worksheet2->UsedRange->Rows[2]->Cells[14]->value);  
        
        

        erhalte ich string(1890) "aaaaaaaa...".

        bei

          
          
           For Each Zeile In Bereich.Rows  
              For Each Zelle In Zeile.Cells  
                 // das If für des etwaige Kapselzeichen mal weggelassen  
                 strTemp = strTemp & CStr(Zelle.Text) & Trennzeichen  
        
        

        kommt beim Auslesen (var_dump()) der entsprechenden Zelle des CSV mit php dann
        string(1024) "aaaaaaaaaa...".

        Ist das "CStr()" vielleicht falsch? Der Rest ist ja quasi ident, nur bei PHP "->" statt ".".

        Dank und Gruß und baldmal erstmal schlafen,

        frankx

        1. Hellihello Vinzenz,

          also:

          For Each Zeile In Bereich.Rows

          • gibt Zeile in Rows

          For Each Zelle In Zeile.Cells

          • gibt Zelle für jede Cells
                 bisher:
                 ...
                 Zelle.Text
                 ...
          • gibt wohl die Eigenschaft "Text" von ...Rows[x].Cells[y]

          habbich nun im php-Script geschaut, da wird die Eigenschaft "->value" bentutzt.

          Im VBA erhalte ich nun mit
               neu:
               ...
               Zelle.Value
               ....

          auf den ersten Blick den Kompletten Zeichen/Sting-Inhalt der Zelle.

          So, nun erstmal ab in die Heia. Ob das FTP dann per Batchdatei und wie so eine Batchdatei aus dem Excel-VBA angestossen werden kann dann hoffentlich morgen.

          Dank und Gruß,

          frankx

        2. Hallo

          Mein Problem, so meine ich mich jetzt - nicht nochmal getestet - zu erinnern war, dass Zellen nach ca. 1000 Zeichen abgeschnitten werden.  Das hatte ich vorhin auch mal angedacht, das nochmal zu testen und dann entsprechend zu posten, wie diese 1000-Zeichen-Beschränkung aufgehoben werden kann.

          ich kann das Problem nicht nachvollziehen (Excel 2007)

          Ist das "CStr()" vielleicht falsch? Der Rest ist ja quasi ident, nur bei PHP "->" statt ".".

          CStr ist überflüssig, da die Eigenschaft Range.Text eh' vom Datentyp String ist.

          Weiter möchte ich anmerken, dass Du doch weißt, dass man Skripte sauber
          strukturiert. Ja, das gilt auch für VBA. Ja, das geht auch mit VBA.

          Noch eine Anmerkung: Ein Filehandle besorgt man sich mit der Funktion FreeFile().

          Freundliche Grüße

          Vinzenz

          1. Hellihello Vinzenz,

            Mein Problem, so meine ich mich jetzt - nicht nochmal getestet - zu erinnern war, dass Zellen nach ca. 1000 Zeichen abgeschnitten werden.  Das hatte ich vorhin auch mal angedacht, das nochmal zu testen und dann entsprechend zu posten, wie diese 1000-Zeichen-Beschränkung aufgehoben werden kann.

            ich kann das Problem nicht nachvollziehen (Excel 2007)

            Tja schau, da gehen die "Probleme" schon los (;-). Hängt dann von der Excelversion des Users ab.

            CStr ist überflüssig, da die Eigenschaft Range.Text eh' vom Datentyp String ist.

            Jap. Aber Cells[x].Text, oder?

            Weiter möchte ich anmerken, dass Du doch weißt, dass man Skripte sauber
            strukturiert. Ja, das gilt auch für VBA. Ja, das geht auch mit VBA.

            Danke (;-)! Ja, das hatte ich mal vor einiger Zeit so einfach übernommen. Erst langsam dämmert mir, was da steht. Mittlerweile mehr als vorher.

            Kannst Du denn (s. nachfolgenden Post, war schon geschrieben), dass

            Zelle in Zeilen.Cells ... Zelle.Text was anderes ausgibt als Zelle.value? Bei 2007 offenbar nicht.

            Noch eine Anmerkung: Ein Filehandle besorgt man sich mit der Funktion FreeFile().

            Gut, hebich mir für morgen auf. Vielleicht schaff ichs ja, den Code strukturiert zu posten, inklusive nachfolgendem Aufruf einer Batchdatei fürs FTP (da hab ich schon eine Vorlage, auch noch zu strukturieren (;-)).

            Guts Nächtle,
            Dank und Gruß,

            frankx

          2. Hellihello Vinzenz,

            Noch eine Anmerkung: Ein Filehandle besorgt man sich mit der Funktion FreeFile().

            Nun habe ich ein Beispiel aus der Hilfe ins Visual-Basic-Fenster kopiert mit Sub ... () drumrum:

            Sub wasneues()
            Dim Index1, Dateinummer
            For Index1 = 1 To 5    ' Schleife 5 mal
                    ' durchlaufen.
                Dateinummer = FreeFile    ' neue Datei-Nr.
                    ' bestimmen.
                Open "TEST" & Index1 For Output As #Dateinummer    ' Dateiname
                    ' erstellen.
                Write #Dateinummer, "Beispieldaten."    ' Text ausgeben.
                Close #Dateinummer    ' Datei schließen.
            Next Index1
            End Sub

            Dann gehe ich auf Sub und drücke das Start-Pfeilchen.

            Irgendie hätte ich jetzt auch gemäß Hilfebeschreibung gedacht, da müssten dann Dateien im Verzeichnis erscheinen, in dem die Excel-Datei (Workbook) liegt:

            "FreeFile-Funktion (Beispiel)
            In diesem Beispiel wird die FreeFile-Funktion verwendet, um die nächste verfügbare Dateinummer zurückzugeben. In der Schleife werden fünf Dateien zur Ausgabe geöffnet und mit Beispieldaten beschrieben."

            Ist aber nicht. Schlauchstehende Müdigkeit, ich träum vermutlich schon.

            Dank und Gruß,

            frankx

            Ps. Gibts sowas wie alert()/trace()? Oder wie kann ich zB. Variableninhalte mal zur Ansicht testweise ausgeben?

          3. Hellihello Vinzenz,

            die Funktion MsgBox() hab ich mittlerweile gefunden. Auch ein kleines Script, dass ein Filehandle benutzt, bei mir aber noch Fragen hinterlässt. Vielleicht hättest Du ja das ein oder andere Stichwort?

            Sub TextDateiErstellen()
              Dim exportfile$, TB As Worksheet, z%, TMP$

            haben das "$" und das "%" eine Bedeutung?
            As Worksheet bedeutet, dass TB ein Worksheet=Tabellenblatt ist (werden soll)?

            exportfile = "C:\test.txt"
                Dateinummer = FreeFile

            gibt ein Dateihandle. Ich weiß zwar nicht wirklich, was das macht, ist aber so wohl.

            Set TB = ThisWorkbook.Worksheets(1)

            nimm Worksheet Nummer 1

            'Die folgende Zeile erzeugt eine neue Datei mit dem angegebenen Namen
                'im angegebenen Pfad
                Open exportfile For Output As #Dateinummer

            ist ja kommentiert. Was aber genau meint "For Output"? Eine Funktion ist es ja nicht, immerhin wurde hier wohl kaum geplenkt (;-).
            wieso eine Raute vor "Dateinummer"?

            'Die beiden Schleifen beziehen alle belegten Zellen in die zu erstellende Textdatei ein
                For z = 1 To TB.UsedRange.Rows.Count
                    For s = 1 To TB.UsedRange.Columns.Count
                      'Das Semikolon ist durch jedes beliebige Feldtrennzeichen ersetzbar
                        TMP = TMP & CStr(TB.Cells(z, s).Text) & ";"
                    Next s
                    'Damit am Ende jeder Zeile, also nach der letzten Zelle kein Strichpunkt mehr gesetzt wird,
                    'muss das letzte Zeichen wieder abgezogen werden
                    TMP = Left(TMP, Len(TMP) - 1)
                    'Print fügt hier immer eine Zeile zur bestehenden Textdatei hinzu
                    Print #Dateinummer, TMP

            Druck in die Datei, die das Dateihandle (mit der Raute) bezeichnet - egal wie der Dateinamen ist, und zwar schubse da TMP rein.

            'Die Variable TMP muss vor der Aufnahme der nächsten Zeile wieder geleert werden
                    TMP = ""
                Next z
                Close #Dateinummer

            Mach die Datei zu, also "ich habe fertisch".

            End Sub

            Noch eine Anmerkung: Ein Filehandle besorgt man sich mit der Funktion FreeFile().

            warum fehlen da oben die Klammern "()" bei Freefile?

            Nebenbei vielleicht noch eine kurze Anregung, mit welchem Zauberwort eine test.bat losgetreten werden könnte? Irgendwie kommt mir das alles etwas amorph vor. In der Hilfe sind so wenig Querverweise. Bei InputMessagebox wird zB. nicht wie im PHP-Manual auf andere verwandte Funktionen verwiesen, wie MsgBox oder so.

            Dank und Gruß,

            frankx

            1. Hellihello SELF

              Sub TextDateiErstellen()
                Dim exportfile$, TB As Worksheet, z%, TMP$

              haben das "$" und das "%" eine Bedeutung?

              Sind deprecated Typenklassen-shortcuts

              As Worksheet bedeutet, dass TB ein Worksheet=Tabellenblatt ist (werden soll)?

              yes

              exportfile = "C:\test.txt"
                  Dateinummer = FreeFile

              gibt ein Dateihandle. Ich weiß zwar nicht wirklich, was das macht, ist aber so wohl.

              Warum das "()" fehlt, ist mir immer noch unklar. Immerhin wird mit FreeFile ein Datenkanal freigegeben, der als Referenznummer auf die Datei gilt.

              Set TB = ThisWorkbook.Worksheets(1)

              nimm Worksheet Nummer 1

              jo, wird wohl.

              'Die folgende Zeile erzeugt eine neue Datei mit dem angegebenen Namen
                  'im angegebenen Pfad
                  Open exportfile For Output As #Dateinummer

              ist ja kommentiert. Was aber genau meint "For Output"? Eine Funktion ist es ja nicht, immerhin wurde hier wohl kaum geplenkt (;-).
              wieso eine Raute vor "Dateinummer"?

              'Die beiden Schleifen beziehen alle belegten Zellen in die zu erstellende Textdatei ein
                  For z = 1 To TB.UsedRange.Rows.Count
                      For s = 1 To TB.UsedRange.Columns.Count
                        'Das Semikolon ist durch jedes beliebige Feldtrennzeichen ersetzbar
                          TMP = TMP & CStr(TB.Cells(z, s).Text) & ";"
                      Next s
                      'Damit am Ende jeder Zeile, also nach der letzten Zelle kein Strichpunkt mehr gesetzt wird,
                      'muss das letzte Zeichen wieder abgezogen werden
                      TMP = Left(TMP, Len(TMP) - 1)
                      'Print fügt hier immer eine Zeile zur bestehenden Textdatei hinzu
                      Print #Dateinummer, TMP

              Druck in die Datei, die das Dateihandle (mit der Raute) bezeichnet - egal wie der Dateinamen ist, und zwar schubse da TMP rein.

              Raute ist hier Syntaxbestandteil für den File-Channel.

              'Die Variable TMP muss vor der Aufnahme der nächsten Zeile wieder geleert werden
                      TMP = ""
                  Next z
                  Close #Dateinummer

              Mach die Datei zu, also "ich habe fertisch".

              dito.

              Noch eine Anmerkung: Ein Filehandle besorgt man sich mit der Funktion FreeFile().

              warum fehlen da oben die Klammern "()" bei Freefile?

              Die Klammer ist wohl korrekter.

              Nebenbei vielleicht noch eine kurze Anregung, mit welchem Zauberwort eine test.bat losgetreten werden könnte? Irgendwie kommt mir das alles etwas amorph vor. In der Hilfe sind so wenig Querverweise. Bei InputMessagebox wird zB. nicht wie im PHP-Manual auf andere verwandte Funktionen verwiesen, wie MsgBox oder so.

              Die Frage ist noch unbeantwortet für mir.

              SELF-Dank und Gruß,

              frankx

              1. Hellihello SELF

                Nebenbei vielleicht noch eine kurze Anregung, mit welchem Zauberwort eine test.bat losgetreten werden könnte?
                Die Frage ist noch unbeantwortet für mir.

                nimm dies, Schurke: Shell("test.bat")

                aber nur mit kompletter Pfadangabe

                Dank und Gruß,

                frankx

            2. Hallo Frank

              die Funktion MsgBox() hab ich mittlerweile gefunden. Auch ein kleines Script, dass ein Filehandle benutzt, bei mir aber noch Fragen hinterlässt. Vielleicht hättest Du ja das ein oder andere Stichwort?

              Sub TextDateiErstellen()
                Dim exportfile$, TB As Worksheet, z%, TMP$

              ' Kommentare leitet man in Visual Basic mit einem Hochkomma ein :-)

              ' >> haben das "$" und das "%" eine Bedeutung?

              ' Ja, sie kennzeichnen den Datentyp der Variablen. Wären die Typkennzeichen nicht
               ' angehängt, so wären beide Variablen vom Typ Variant (der auf alles passt)
                  ' % ist das Kennzeichen für eine 16-Byte-Integer
               ' $ ist das Kennzeichen für einen String

              ' Der Datentyp für z ist ungünstig gewählt, da er nicht ausreichend ist:
               ' Ein Excel-Sheet bis zur Version Excel 2003 kann 65536 Zeilen haben, bereits in
               ' diesem Fall benötigt man eine Long Integer

              ' >> As Worksheet bedeutet, dass TB ein Worksheet=Tabellenblatt ist (werden soll)?

              ' Ja, TB kann ein Worksheet-Objekt speichern.

              exportfile = "C:\test.txt"

              ' typischer Fall für einen Parameter Deiner Prozedur

              Dateinummer = FreeFile

              ' >> gibt ein Dateihandle. Ich weiß zwar nicht wirklich, was das macht, ist aber so wohl.

              ' Ein Dateihandle ist einfach eine Zahl. In VB eine zwischen 1 und 511. Du könntest Dir
                 ' eine beliebig wählen (wie vorher die 1) und hoffen, dass es klappt.
                 ' Bei anderen Sprachen liefert die entsprechende Funktion zum Öffnen das Dateihandle,
                 ' eine Zahl, zurück. Auch die Verbindungskennung zu einer DB ist nichts anderes als eine
                 ' Zahl.

              Set TB = ThisWorkbook.Worksheets(1)
                  ' >> nimm Worksheet Nummer 1

              ' Nimm das erste Worksheet in der aktuellen Mappe :-)
                    ' Dieser Index ist glücklicherweise unabhängig von der Einstellung Option Base :-)

              'Die folgende Zeile erzeugt eine neue Datei mit dem angegebenen Namen
                  'im angegebenen Pfad
                  Open exportfile For Output As #Dateinummer

              ist ja kommentiert. Was aber genau meint "For Output"? Eine Funktion ist es ja nicht, immerhin wurde hier wohl kaum geplenkt (;-).
              wieso eine Raute vor "Dateinummer"?

              Die Syntax von Open lautet :-)
              Open Pfadname For Modus [Access Zugriff] [Sperre] As [#]Dateinummer [Len=Satzlänge]

              In der VBA-IDE (Alt+F11) einfach Open eingeben und F1 drücken :-)

              Du möchtest schreiben, d.h. eine Ausgabe in die Datei machen.
              Du befürchtest keinen konkurrierenden Zugriff auf Deine neue Datei, deswegen brauchst Du sie
              auch nicht zu sperren. Ansonsten gelten hier die Ausführungen von Christian Seiler.

              'Die beiden Schleifen beziehen alle belegten Zellen in die zu erstellende Textdatei ein
                  For z = 1 To TB.UsedRange.Rows.Count
                      For s = 1 To TB.UsedRange.Columns.Count
                        'Das Semikolon ist durch jedes beliebige Feldtrennzeichen ersetzbar
                          TMP = TMP & CStr(TB.Cells(z, s).Text) & ";"
                      Next s
                      'Damit am Ende jeder Zeile, also nach der letzten Zelle kein Strichpunkt mehr gesetzt wird,
                      'muss das letzte Zeichen wieder abgezogen werden
                      TMP = Left(TMP, Len(TMP) - 1)
                      'Print fügt hier immer eine Zeile zur bestehenden Textdatei hinzu
                      Print #Dateinummer, TMP

              Druck in die Datei, die das Dateihandle (mit der Raute) bezeichnet - egal wie der Dateinamen ist, und zwar schubse da TMP rein.

              'Die Variable TMP muss vor der Aufnahme der nächsten Zeile wieder geleert werden
                      TMP = ""
                  Next z

              Ich würde das heute (da Speicher kein Problem darstellt) anders lösen:
              Klassisches EVA-Prinzip:

              Eingabe:
              Lies den Inhalt Deiner Excelliste in eine geeignete Datenstruktur ein.
              Ein zweidimensionales Array bietet sich an.

              Verarbeitung:
              Maskiere die Einträge, die das Trennzeichen enthalten
              Verbinde die Einträge jeder Zeile zu einer Textzeile

              Ausgabe:
              Schreibe zeilenweise weg.

              Alternativ kannst Du natürlich auch alle Zeilen mit einem Zeilenende joinen
              und dann die ganze Datei in einem Rutsch wegschreiben.

              Noch eine Anmerkung: Ein Filehandle besorgt man sich mit der Funktion FreeFile().

              warum fehlen da oben die Klammern "()" bei Freefile?

              Weil in diesem Fall der einzige und dazu optionale Aufrufparameter der Funktion weggelassen wurde.

              Nebenbei vielleicht noch eine kurze Anregung, mit welchem Zauberwort eine test.bat losgetreten werden könnte? Irgendwie kommt mir das alles etwas amorph vor. In der Hilfe sind so wenig Querverweise. Bei InputMessagebox wird zB. nicht wie im PHP-Manual auf andere verwandte Funktionen verwiesen, wie MsgBox oder so.

              Shell(pathname[,windowstyle])
              Bitte in der Onlinehilfe nachsehen, was Du damit alles anstellen kannst.
              Die Batchdatei würdest übrigens nicht direkt starten, sondern eine Instanz
              des Kommandozeileninterpreters, der Du die Batchdatei als Parameter übergibst.

              Noch etwas zu Funktionen:

              ' Standardmäßig werden Parameter by Reference übergeben, willst Du nur Werte übergeben
              ' so verwende ByVal. Der Rückgabewert erfolgt über die implizit angelegte Variable, die
              ' den gleichen Namen wie die Funktion selbst trägt:
              ' Beispiel:
              Function beispiel(ByVal arg1 As Integer, ByRef arg2 As String) As String
               ' Implizit enthalten:
               ' Dim beispiel As String

              ' Baue den Rückgabewert zusammen
               ' Ein _ am Ende der Zeile leitet eine Zeilenfortsetzung ein
               ' Die Konstante vbCrLf ist ein Zeilenende (Windows-Style)
               ' arg1 wird implizit zu einer Zeichenkette umgewandelt
               beispiel = "Hallo Welt!" & vbCrLf & _
                arg2 & vbCrLf & arg1
              End Function

              Aufruf:
              Dim myString As String
              myString = beispiel(7, "Beispieltext")

              ' Erzeuge eine Ausgabe ins Direktfenster (in der VBA-IDE über Ansicht->Direktfenster einblenden)
              debug.pring myString

              Im Überwachungsfenster kannst Du Dir den Inhalt von Variablen anzeigen lassen,
              im Code Break- und Watchpoints setzen. Die VBA-IDE bietet schon einiges an Debugkomfort.

              Freundliche Grüße

              Vinzenz

              1. Hellihello Vinzenz,

                besten Dank:

                Du möchtest schreiben, d.h. eine Ausgabe in die Datei machen.
                Du befürchtest keinen konkurrierenden Zugriff auf Deine neue Datei, deswegen brauchst Du sie
                auch nicht zu sperren. Ansonsten gelten hier die Ausführungen von Christian Seiler.

                Sollte ich da  nach "Ausführungn von Christian Seiler" googeln? Oder hätte ich sonstwas verpeilt?

                Danke Vielmals für die Ausführung,

                frankx

                1. Hallo

                  Du befürchtest keinen konkurrierenden Zugriff auf Deine neue Datei, deswegen brauchst Du sie
                  auch nicht zu sperren. Ansonsten gelten hier die Ausführungen von Christian Seiler.
                  Sollte ich da  nach "Ausführungn von Christian Seiler" googeln? Oder hätte ich sonstwas verpeilt?

                  Nein, die Suche hier bemühen.

                  Ok, das kommt davon, wenn man eine Antwort offline verfasst :-)

                  Ich meinte: http://aktuell.de.selfhtml.org/artikel/programmiertechnik/dateisperren/

                  und ansonsten hattest Du einiges ja schon selbst herausgefunden.

                  Freundliche Grüße

                  Vinzenz

                  1. Hellihello Vinzenz,

                    Debug.Print ist mein König (;-).

                    my_join = Join(ActiveWorkbook.ActiveSheet.Rows(3).Cells, "aaa")

                    klappt nicht. Vermutlich ist *.Cells nicht vom Typ Array, oder?

                    Dank und Gruß,

                    frankx

                    1. Hallo

                      Debug.Print ist mein König (;-).

                      my_join = Join(ActiveWorkbook.ActiveSheet.Rows(3).Cells, "aaa")

                      klappt nicht. Vermutlich ist *.Cells nicht vom Typ Array, oder?

                      Nein, natürlich nicht. Es gibt ein Range-Objekt zurück, das die Zellen
                      im entsprechenden Bereich enthält.

                      Freundliche Grüße

                      Vinzenz

                      1. Hellihello

                        my_join = Join(ActiveWorkbook.ActiveSheet.Rows(3).Cells, "aaa")

                        klappt nicht. Vermutlich ist *.Cells nicht vom Typ Array, oder?

                        Nein, natürlich nicht. Es gibt ein Range-Objekt zurück, das die Zellen
                        im entsprechenden Bereich enthält.

                        Das ist aber nicht Vergleichbar mit einem PHP-Objekt, oder? Auch wenn ich das mit For Each durchlaufen kann und wie bei einem Array mit my_Array(3) auch my_Range_Objekt(3) den Wert abrufen.

                        Wie denn umwandeln des Objekt-Ranges in ein Array frag ick mir.

                        Dank und Gruß,

                        frankx

                        1. Hallo Frank,

                          Nein, natürlich nicht. Es gibt ein Range-Objekt zurück, das die Zellen
                          im entsprechenden Bereich enthält.

                          Das ist aber nicht Vergleichbar mit einem PHP-Objekt, oder? Auch wenn ich das mit For Each durchlaufen kann und wie bei einem Array mit my_Array(3) auch my_Range_Objekt(3) den Wert abrufen.

                          es gibt viele Dinge, die man mit For Each durchlaufen kann und die kein Array sind, z.B. Collections, Dictionaries und in Excel halt eben auch ein Range-Objekt.

                          Wie denn umwandeln des Objekt-Ranges in ein Array frag ick mir.

                          In BASIC musst Du ein Array anlegen. Dabei musst Du den Datentyp angeben, den
                          Dein Array aufnehmen soll (oder es ist halt Variant, dann kannst Du alles reinpacken - Nein, ich halte das nicht für eine gute Idee.)

                          Beispiel:

                          Dim myArray(9) As Integer

                          erstellt ein Array mit einer bestimmten Anzahl (ja wievielen denn) von "Zeilen", auf die Du über ihren Index zugreifen kannst.

                          Mit der Option-Base-Anweisung zu Beginn des Moduls regelst Du, ob die
                          Indizierung mit 0 (bei VBA Standard) oder mit 1 beginnt.

                          Arrays (Suchwort: Datenfelder) können in der Größe verändert werden, dazu dient die ReDim-Anweisung. ReDim Preserve sorgt dafür, dass die Daten dabei
                          erhalten bleiben.

                          Lege also ein Array an, redimensioniere auf die Anzahl der Spalten.
                          Weise jedem Arrayelement den Inhalt der Text-Eigenschaft einer Zelle zu.

                          Ach so:
                          Über debug.print kannst Du Dir bei formatierten Zellen, z.B. mit Währungsformat, mal den Unterschied zwischen

                          cell.Text und cell.Value

                          anzeigen lassen.

                          Freundliche Grüße

                          Vinzenz

                          1. Hellihello Vinzenz,

                            Ach so:
                            Über debug.print kannst Du Dir bei formatierten Zellen, z.B. mit Währungsformat, mal den Unterschied zwischen

                            cell.Text und cell.Value

                            Währung:
                             2
                            Ende Cells - Begin Text
                            2,00 €
                            Ende Text - Begin Value
                             2

                            Datum:

                            18.07.2005
                            Ende Cells - Begin Text
                            18.07.2005
                            Ende Text - Begin Value
                            18.07.2005

                            Aber bei mir bleibts: Die Eigenschaft *.Rows(x).Cells(y).Text schneidet nach 1024 Zeichen ab, nicht aber bei *.Rows(x).Cells(y) und nicht bei *.Rows(x).Cells(y).Value

                            Dank und Gruß,

                            frankx

                            1. Hallo Frank,

                              Aber bei mir bleibts: Die Eigenschaft *.Rows(x).Cells(y).Text schneidet nach 1024 Zeichen ab, nicht aber bei *.Rows(x).Cells(y) und nicht bei *.Rows(x).Cells(y).Value

                              ich hab' in einer VM das Verhalten in Office 2000 überprüft - und mir anschließend die Spezifikationen in der Hilfe angeschaut:

                              • Excel 2000 (damit gültig von Excel 97 bis Excel 2003):

                              Länge des Inhalts der Zelle (Text):
                                32.767 Zeichen. Nur 1.024 Zeichen werden in einer Zelle angezeigt;
                                alle 32.767 werden in der Formelleiste angezeigt.

                              Offensichtlich greift die Eigenschaft Text auf die Anzeige, deswegen kommst Du
                              mit Text auch nur an die ersten 1024 Zeichen heran. Wenn Du Dir sicher sein kannst, dass Du durch die Formatierung "erzeugten" Inhalt nicht benötigst,
                              dann kannst Du problemlos auf die Eigenschaft Value zugreifen.

                              • Bei Excel 2007 fällt die Anzeigebegrenzung weg, daher "funktioniert" bei mir
                                  auch Text. Weiterhin sind 1.048.576 Zeilen und 16.384 Spalten möglich im
                                  Vergleich zu 65536 Zeilen und 256 Spalten bei bisherigen Versionen. Die
                                  Entwicklung bei der RAM-Ausstattung macht's möglich, auch wenn das hier
                                  nicht jedem gefällt, siehe https://forum.selfhtml.org/?t=161245&m=1049575ff.

                              Ich finde das hingegen beeindruckend, vor allem auf meinem mehr als drei Jahre
                              alten und dennoch leisen Notebook, das nur ca. 20W im Netzbetrieb zieht.

                              Freundliche Grüße

                              Vinzenz

                          2. Hellihello Vinzenz,

                            so schauts bei mir jetzt aus:

                              
                            Sub create_joined_delimited_table()  
                              
                            Dim UrsprungsZeile, UrsprungsSpalte As Object  
                            Dim Spaltenanzahl, Zeilenanzahl As Integer  
                            Dim Spaltendelimiter, Zeilendelimiter As String  
                              
                            Dim Zeilen() As String  
                            Dim Spalten() As String  
                            Dim Join_Tabelle As String  
                              
                            Zeilenanzahl = ActiveWorkbook.ActiveSheet.UsedRange.Rows.Count  
                            Spaltenanzahl = ActiveWorkbook.ActiveSheet.UsedRange.Rows(1).Cells.Count  
                              
                            ReDim Zeilen(Zeilenanzahl) As String  
                            ReDim Spalten(Spaltenanzahl) As String  
                              
                            Spaltendelimiter = "§§§§§"  
                            Zeilendelimiter = "°°°°°"  
                              
                            For Zeilennummer = 1 To Zeilenanzahl Step 1  
                                For Spaltennummer = 1 To Spaltenanzahl Step 1  
                                    Spalten(Spaltennummer) = ActiveWorkbook.ActiveSheet.UsedRange.Rows(Zeilennummer).Cells(Spaltennummer).Value  
                                Next  
                                Zeilen(Zeilennummer) = Join(Spalten, Spaltendelimiter)  
                            Next  
                                Join_Tabelle = Join(Zeilen, Zeilendelimiter)  
                            Debug.Print Join_Tabelle  
                              
                            End Sub  
                            
                            

                            Dank soweit für deine Hilfe und Gruß aus Berlin,

                            frankx

                            1. Hellihello Vinzenz,

                              könntest Du vielleicht noch bei einer Kleinigkeit nachschubbsen:

                              Mit der Option-Base-Anweisung zu Beginn des Moduls regelst Du, ob die

                              Indizierung mit 0 (bei VBA Standard) oder mit 1 beginnt.

                              Dim Spalten() As String
                              Wie krieg ich da die Option-Base-Anweisung rein?

                              Dank und Gruß,

                              frankx

                              1. Hallo Frank

                                ' ---------------------------------------
                                ' Beginn des Moduls
                                ' ---------------------------------------
                                ' Indiziere Arrays von 0 an, wie gewohnt
                                Option Base 0

                                ' Viel wichtiger
                                ' Variablen müssen deklariert werden
                                Option Explicit

                                Mit der Option-Base-Anweisung zu Beginn des Moduls regelst Du, ob die
                                Indizierung mit 0 (bei VBA Standard) oder mit 1 beginnt.

                                Dim Spalten() As String
                                Wie krieg ich da die Option-Base-Anweisung rein?

                                siehe oben ...

                                Freundliche Grüße

                                Vinzenz

                            2. Hallo Frank,

                              Zeilenanzahl = ActiveWorkbook.ActiveSheet.UsedRange.Rows.Count
                              Spaltenanzahl = ActiveWorkbook.ActiveSheet.UsedRange.Rows(1).Cells.Count

                              Es gibt nicht nur Rows, es gibt auch Columns :-)

                              Spaltendelimiter = "§§§§§"

                              Deklariere diesen als Konstante außerhalb der Prozedur.

                              Zeilendelimiter = "°°°°°"

                              Warum nimmst Du keine Zeilenumbruch (vbCrLf)?
                              Klar, Du musst auch Zellen mit Zeilenumbruch maskieren.

                              Was passiert, wenn Du einfach alle Zellinhalte maskierst?

                              Derzeit maskierst Du ja überhaupt nicht und verläßt Dich auf die Wahl Deiner Delimiter.

                              Freundliche Grüße

                              Vinzenz

                              1. Hellihello Vinzenz,

                                heute etwas später mal kurz nur - Dank für Deine Antwort.

                                Hallo Frank,

                                Zeilenanzahl = ActiveWorkbook.ActiveSheet.UsedRange.Rows.Count
                                Spaltenanzahl = ActiveWorkbook.ActiveSheet.UsedRange.Rows(1).Cells.Count

                                Es gibt nicht nur Rows, es gibt auch Columns :-)

                                Spaltendelimiter = "§§§§§"

                                Deklariere diesen als Konstante außerhalb der Prozedur.

                                Zeilendelimiter = "°°°°°"

                                Warum eigentlich außerhalb der Prozeder? Prozedur = Sub? Und was ist dann eine "Property"?

                                ' ---------------------------------------
                                ' Beginn des Moduls
                                ' ---------------------------------------
                                ' Indiziere Arrays von 1 an, weil weiß ich auch grad nicht, wegen des Zeilen und Spaltenzählers von 1 TO Zeilen/Spaltenzahl
                                 Option Base 1

                                ' Viel wichtiger
                                ' Variablen müssen deklariert werden
                                Option Explicit

                                ' Deklariere diesen als Konstante außerhalb der Prozedur
                                Const Spaltendelimiter = "§§§§§"
                                Const Zeilendelimiter = "°°°°°"

                                Sub create_joined_delimited_table()

                                Dim UrsprungsZeile, UrsprungsSpalte As Object
                                Dim Spaltenanzahl, Zeilenanzahl, Zeilennummer, Spaltennummer As Integer
                                'Dim Spaltendelimiter, Zeilendelimiter As String

                                Dim Zeilen() As String
                                Dim Spalten() As String
                                Dim Join_Tabelle As String

                                Zeilenanzahl = ActiveWorkbook.ActiveSheet.UsedRange.Rows.Count
                                Spaltenanzahl = ActiveWorkbook.ActiveSheet.UsedRange.Columns.Count

                                ReDim Zeilen(Zeilenanzahl) As String
                                ReDim Spalten(Spaltenanzahl) As String

                                For Zeilennummer = 1 To Zeilenanzahl Step 1
                                    For Spaltennummer = 1 To Spaltenanzahl Step 1
                                        Spalten(Spaltennummer) = ActiveWorkbook.ActiveSheet.UsedRange.Rows(Zeilennummer).Cells(Spaltennummer).Value
                                    Next
                                    Zeilen(Zeilennummer) = Join(Spalten, Spaltendelimiter)
                                Next
                                    Join_Tabelle = Join(Zeilen, Zeilendelimiter)
                                    Debug.Print Join_Tabelle
                                Debug.Print ("fertisch")
                                End Sub

                                Derzeit maskierst Du ja überhaupt nicht und verläßt Dich auf die Wahl Deiner Delimiter.

                                Ehrlichgesagt kapier ich die Maskerade nicht. Was hab ich davon, dass ich mit

                                Const Delimiter="°°°"
                                Const Maske="§"

                                bei
                                Zelle irgendwo aaaa°°°aaa dann §aaa°°°aaa§ draus mache. ich möchte ja das dingens mit PHPs explode zerlegen am Delimiter.

                                Ich weiß zwar, dass man möglichst 100% Lösungen anstreben sollte, aber es erscheint mir fast möglich, Delimiter zu finden, die nicht im Text auftauchen wie [°°°°°°] und [#§#] zum Beispiel. Möglichkeit wäre noch, die kompletten Zellen Sicherheitshalber daraufhin zu durchsuchen, und dann entweder den Delimiter anpassen/ergänzen oder den Vorgang abbrechen und auf die dann sowieso mit Fehlerhaftem Inhalt behaftete Zelle hinzuweisen.

                                Dank und Gruß,

                                frankx

                                1. Hallo

                                  Spaltendelimiter = "§§§§§"
                                  Deklariere diesen als Konstante außerhalb der Prozedur.

                                  Warum eigentlich außerhalb der Prozeder?

                                  Ganz einfach: Es ist eine gute Idee - und zwar völlig unabhängig von der
                                  verwendeten Programmiersprache - solche hart codierten Werte am Anfang einer
                                  Datei, hier am Anfang des Moduls stehen zu haben.

                                  Weiterhin ist es eine gute Idee, diese Konstanten einer Funktion/Prozedur als
                                  Aufrufparameter mitzugeben, damit wird Deine Funktion/Prozedur allgemeiner
                                  verwendbar - ohne komplexer zu werden.

                                  Prozedur = Sub?

                                  In VB: ja, siehe auch Wikipedia.
                                  (bewußt die Begriffsklärungsseite, die Spezialseite lohnt sich hier in
                                  diesem Zusammenhang nicht)

                                  Und was ist dann eine "Property"?

                                  Eine Eigenschaft eines Objektes, viel besser als eine globale Variable :-)
                                  Der Zusammenhang Deiner Aufgabe mit einem Property ist mir unklar.

                                  [...]

                                  Derzeit maskierst Du ja überhaupt nicht und verläßt Dich auf die Wahl Deiner Delimiter.

                                  Ehrlichgesagt kapier ich die Maskerade nicht. Was hab ich davon, dass ich mit

                                  Const Delimiter="°°°"
                                  Const Maske="§"

                                  Du solltest ja auch ganz andere verwenden.

                                  Zelle irgendwo aaaa°°°aaa dann §aaa°°°aaa§ draus mache. ich möchte ja das dingens mit PHPs explode zerlegen am Delimiter.

                                  Nein, das möchtest Du nicht.

                                  Ich weiß zwar, dass man möglichst 100% Lösungen anstreben sollte, aber es erscheint mir fast möglich, Delimiter zu finden, die nicht im Text auftauchen wie [°°°°°°] und [#§#] zum Beispiel.

                                  Ja eben. Genau aus diesem Grund haben sich Leute schon Gedanken gemacht und
                                  eine (nicht perfekte) Spezifikation für dieses Problem erstellt. Ich dachte,
                                  dass Du genau diese Spezifikation im Auge hättest, schließlich speicherst Du
                                  Deine Datei als

                                  <timestamp>.csv

                                  ab. PHP verfügt über die Funktion fgetcsv, um solche Dateien zu verarbeiten.
                                  Andere Programmiersprachen verfügen über vergleichbare Funktionen.
                                  CSV ist ein übliches Format, nutze es.

                                  Freundliche Grüße

                                  Vinzenz

                                  1. Hellihello Vinzenz,

                                    Du solltest ja auch ganz andere verwenden.

                                    Zelle irgendwo aaaa°°°aaa dann §aaa°°°aaa§ draus mache. ich möchte ja das dingens mit PHPs explode zerlegen am Delimiter.

                                    Nein, das möchtest Du nicht.

                                    Ich weiß zwar, dass man möglichst 100% Lösungen anstreben sollte, aber es erscheint mir fast möglich, Delimiter zu finden, die nicht im Text auftauchen wie [°°°°°°] und [#§#] zum Beispiel.

                                    Ja eben. Genau aus diesem Grund haben sich Leute schon Gedanken gemacht und
                                    eine (nicht perfekte) Spezifikation für dieses Problem erstellt. Ich dachte,
                                    dass Du genau diese Spezifikation im Auge hättest, schließlich speicherst Du
                                    Deine Datei als

                                    <timestamp>.csv

                                    ab. PHP verfügt über die Funktion fgetcsv, um solche Dateien zu verarbeiten.
                                    Andere Programmiersprachen verfügen über vergleichbare Funktionen.
                                    CSV ist ein übliches Format, nutze es.

                                    An diesem Punkt war ich noch am Hadern.

                                    Wikipedia meint u.a.: "Die Abkürzung CSV steht dabei für Character Separated Values...".

                                    So wird ja zB. u.a. ein Semikolon statt Komma verwandt, um Konflikte mit den Dateninhalten zu vermeiden.

                                    Jetzt finde ich unter http://tools.ietf.org/html/rfc4180
                                    "While there are various specifications and implementations for the  CSV format (...), there is no formal  specification in existence, which allows for a wide variety of interpretations of CSV files."

                                    Auch: "Each field may or may not be enclosed in double quotes (however some programs, such as Microsoft Excel, do not use double quotes at all). If fields are not enclosed with double quotes, then
                                    ouble quotes may not appear inside the fields."

                                    Ich Frage mich deshalb:

                                    a) Ist es im Grunde nicht ein (zu Recht) recht beliebiges Format. Ich brauche doch nur Spaltentrenner und Zeilentrenner bekannt geben, und es ist sofort lesbar

                                      
                                      
                                    $Zeilen_noch_als_Text=explode($Zeilentrenner,$Tabelle_als_CSV);  
                                    foreach ($Zeilen_noch_als_Text as $Zeile_als_Text) {  
                                       $Zeilen[]=explode($Spaltendelimiter,$Zeile_als_Text);  
                                    }  
                                    
                                    

                                    b) ist diese Variante nicht doch auch CSV und erspart:
                                      i das Maskieren des Spaltendelimiters innerhalb der Datensätze
                                      ii das Verdoppeln des  Umgebungszeichens ("If double-quotes are used to enclose fields, then a double-quote appearing inside a field must be escaped by preceding it with another double quote.  For example: "aaa","b""bb","ccc" ")

                                    c) was ist, wenn jetzt ";" der Spaltentrenner und '"' das Datenfeld-Enclosure-Zeichen ist. Im Datensatz steht nun 'abc"","CRLF","aaa' - das wird dann masikiert zu  'abc"""",""CRLF"",""aaa'?

                                    Im Grunde sehe ich es wie Du, dass spezifizierte Datenformate gentutz t werden sollten, bin hier aber etwas ratlos, ob das nicht mit beliebigen Trennern doch im Rahmen dieser eher unspezifischen Spezifikation liegt und dies nicht wirklich eine relativ sichere und einfache Lösung ist.

                                    Dank und Gruß,

                                    frankx

                                    1. Hallo Frank,

                                      Ja eben. Genau aus diesem Grund haben sich Leute schon Gedanken gemacht und
                                      eine (nicht perfekte) Spezifikation für dieses Problem erstellt. Ich dachte,

                                      ich betone "nicht perfekte", aber sehr brauchbare

                                      dass Du genau diese Spezifikation im Auge hättest, schließlich speicherst Du
                                      Deine Datei als

                                      <timestamp>.csv

                                      ab. PHP verfügt über die Funktion fgetcsv, um solche Dateien zu verarbeiten.
                                      Andere Programmiersprachen verfügen über vergleichbare Funktionen.
                                      CSV ist ein übliches Format, nutze es.

                                      An diesem Punkt war ich noch am Hadern.

                                      Wikipedia meint u.a.: "Die Abkürzung CSV steht dabei für Character Separated Values...".

                                      Äh ja, und als Trennzeichen wird ein *Zeichen* genommen.

                                      So wird ja zB. u.a. ein Semikolon statt Komma verwandt, um Konflikte mit den Dateninhalten zu vermeiden.

                                      Nö, das ist Unsinn. Es kann prinzipiell gesehen jedes Zeichen verwendet werden. Semikolon, Komma und Tabulator sind wahrscheinlich die am häufigsten
                                      verwendeten Zeichen.

                                      Jetzt finde ich unter http://tools.ietf.org/html/rfc4180
                                      "While there are various specifications and implementations for the  CSV format (...), there is no formal  specification in existence, which allows for a wide variety of interpretations of CSV files."

                                      Das meinte ich mit "nicht perfekt".

                                      Auch: "Each field may or may not be enclosed in double quotes (however some programs, such as Microsoft Excel, do not use double quotes at all). If fields are not enclosed with double quotes, then
                                      ouble quotes may not appear inside the fields."

                                      Keine Ahnung, wo das steht - aber: Es stimmt nicht. Es ist falsch :-)
                                      Excel verwendet sehr wohl doppelte Anführungszeichen (zumindest Excel 2007).

                                      Ich Frage mich deshalb:

                                      a) Ist es im Grunde nicht ein (zu Recht) recht beliebiges Format. Ich brauche doch nur Spaltentrenner und Zeilentrenner bekannt geben, und es ist sofort lesbar

                                      Nun, ob das unter die Spezifikation fällt, weiß ich nicht - und sofort lesbar,
                                      für mich zumindest nicht.

                                      b) ist diese Variante nicht doch auch CSV und erspart:
                                        i das Maskieren des Spaltendelimiters innerhalb der Datensätze
                                        ii das Verdoppeln des  Umgebungszeichens ("If double-quotes are used to enclose fields, then a double-quote appearing inside a field must be escaped by preceding it with another double quote.  For example: "aaa","b""bb","ccc" ")

                                      Nö, dieses Problem hast Du immer.

                                      Im Grunde sehe ich es wie Du, dass spezifizierte Datenformate gentutz t werden sollten, bin hier aber etwas ratlos, ob das nicht mit beliebigen Trennern doch im Rahmen dieser eher unspezifischen Spezifikation liegt und dies nicht wirklich eine relativ sichere und einfache Lösung ist.

                                      Du hast normalerweise überhaupt kein Problem, wenn Du

                                      a) das üblichste aller Umgebungszeichen verwendest, die doppelten Anführungszeichen
                                      b) das gewählte Umgebungszeichen im Inhalt vorher verdoppelst
                                      c) das üblichste Zeilenende verwendest, einen Zeilenumbruch
                                      d) eines der üblichsten Spaltentrennzeichen verwendest, Semikolon oder Komma

                                      ... und dann fgetcsv nimmst.

                                      Der große Vorteil dieses Vorgehens ist, dass Du Dir die so entstandene Datei
                                      mit jeder Anwendungssoftware, die CSV kann - wie z.B. Excel oder Calc aus
                                      OpenOffice.

                                      Freundliche Grüße

                                      Vinzenz

                                      1. Hellihello Vinzenz,

                                        Du hast normalerweise überhaupt kein Problem, wenn Du

                                        a) das üblichste aller Umgebungszeichen verwendest, die doppelten Anführungszeichen
                                        b) das gewählte Umgebungszeichen im Inhalt vorher verdoppelst
                                        c) das üblichste Zeilenende verwendest, einen Zeilenumbruch
                                        d) eines der üblichsten Spaltentrennzeichen verwendest, Semikolon oder Komma

                                        ... und dann fgetcsv nimmst.

                                        Der große Vorteil dieses Vorgehens ist, dass Du Dir die so entstandene Datei
                                        mit jeder Anwendungssoftware, die CSV kann - wie z.B. Excel oder Calc aus
                                        OpenOffice.

                                        Ja, das klingt überzeugend. Sollte ich dann aber nicht gleich den CSV-Export von Excel Nutzen oder "kann" der das nicht bzw. den wird man ja wohl auch über VBA angsprechen können?

                                        Dank und Gruß,

                                        frankx

                                        1. Hallo

                                          Ja, das klingt überzeugend. Sollte ich dann aber nicht gleich den CSV-Export von Excel Nutzen oder "kann" der das nicht bzw. den wird man ja wohl auch über VBA angsprechen können?

                                          Nutze die SaveAs-Methode des Worksheet-Objektes mit dem FileFormat xlCSV.
                                          Ach ja, kennst Du schon den Objektkatalog?
                                          Den bekommst Du in der VBA-IDE über F2.

                                          Freundliche Grüße

                                          Vinzenz

                                          1. Hellihello Vinzenz,

                                            Nutze die SaveAs-Methode des Worksheet-Objektes mit dem FileFormat xlCSV.

                                            Ja, sieht dann schön aus, mit Kommas, aber escapen tut er innerhalb der Felder dann "," (also Anführungszeichen + Komma + Anführungszeichen) nicht. Wenn ichs mit Excel dann wieder öffne, siehts nicht mehr schön aus (;-), also es stimmt nicht mehr.

                                            Mache ich das aber per Hand Datei/SpeicherUnter/csv dann nimmt Excel Simikolon als Trennzeichen und kanns auch wieder einlesen.

                                            Wie fgetcsv() damit umgeht, hab ich noch nicht getestet. Erstmal innerhalb von Excel bleiben, wenn das sich selbst schon nicht versteht, stimmt ja erstmal was nicht.

                                            » Ach ja, kennst Du schon den Objektkatalog?

                                            Den bekommst Du in der VBA-IDE über F2.

                                            Kannte ich noch nicht, danke für den Tipp. Die SaveAs-_Methode_ findet sich da dann aber nicht, natürlich. Die Hilfe bei o.g. konnte mir auch keinen Aufschluss darüber geben, dass die Paramter (FileName, FileFormat) mit Kommas zu separieren sind. Ist vielleich selbstredende Konvetion bei VBA?

                                            Dank und Gruß,

                                            frankx

                                          2. Hellihello Vinzenz,

                                            Nutze die SaveAs-Methode des Worksheet-Objektes mit dem FileFormat xlCSV.

                                            Zwei Nachteile sehe ich mittlerweile:

                                            1. wähle ich die Methode aus VBA heraus, kommt was anderes heraus (einmal Semikolon, einmal Komma) als übers Menü. Mit "locale:=true" verändert sich u.U. - je nach User-Einstellung - der Spaltendelimiter.

                                            2. Heißt das Dokument nach dieser VBA-Aktion dann anders und ist komplett konvertiert. "Die Nutzerin" hat nun ein anderes benanntes und formatiertes Dokument mit nur einem Arbeitsblatt, ohne es "bermekt" zu haben.

                                            Zu CSV fand ich noch: http://en.wikipedia.org/wiki/Delimiter-separated_values.

                                            "ASCII includes several control characters that are intended to be used as delimiters. They are: 28 file separator, 29 group separator, 30 record separator, 31 unit separator."

                                            Fand ich auch mal interessant.Aber:

                                            "Use of these characters has not achieved widespread adoption; some systems have replaced their control properties with more accepted controls such as CR/LF and TAB."

                                            Im Grund ist ja der Zeilentrenner auch kein "char" mehr, sonder zwei "char"s (spricht man das eigentlich "tschar" wie bei "chair" oder "käir" wie bei "care" und "character" ?)

                                            Schlussendlich wäre aber wohl die weit verbreitet Variante nun diese, wenn ich da Recht verstehe:

                                            Umgebungsdelimiter= >>"<<
                                            Spaltendelimiter= >>;<< (>>,<< mag Excel scheints nicht so)
                                            Zeilendelimiter = >>ASCII(13)ASCII(10)<< (CR/LF)

                                            Die Logik ist wie folgt:

                                            Für jede Zelle
                                             1. wenn der Umgebungsdelimiter vorhanden, dann diesen verdoppeln
                                             2. wenn eins der drei Delimiterzeichen vorhanden, dann Zelle in Umgebungsdelimiter einpacken
                                             3. wenn nicht Zeilenende, nach der Zelle den Spaltendelimiter packen, sonst ist es Zeilenende, dann kommen die beiden Zeilendelimiter.

                                            Für die Logik des Auslesens hieße das:

                                            Steht am Anfang ein Umgebungsdelimiter, ist das Ende der Zelle dort, wo eine ungerade Anzahl von Umgebungsdelimitern vorkommt, und zwar beim letzten Zeichen davon abzüglich desselbigen. Kommt dannach ein  Semikolon, ists ein Zellenende, sonst muss ein CR/LF kommen, dann ists ein Zeilenende; wenn beides nicht zutrifft, ist die Datenstruktur beschädigt.

                                            Dank und Gruß,

                                            frankx

                                            1. Hallo Frank,

                                              Nutze die SaveAs-Methode des Worksheet-Objektes mit dem FileFormat xlCSV.

                                              Zwei Nachteile sehe ich mittlerweile:

                                              1. wähle ich die Methode aus VBA heraus, kommt was anderes heraus (einmal Semikolon, einmal Komma) als übers Menü. Mit "locale:=true" verändert sich u.U. - je nach User-Einstellung - der Spaltendelimiter.
                                              1. Heißt das Dokument nach dieser VBA-Aktion dann anders und ist komplett konvertiert. "Die Nutzerin" hat nun ein anderes benanntes und formatiertes Dokument mit nur einem Arbeitsblatt, ohne es "bermekt" zu haben.

                                              deswegen sagte ich ja: worksheet-Objekt verwenden, nicht das workbook-Objekt :-)
                                              Und ja: Wenn Du das aktuelle Workbook verwendest, befindest Du Dich auf einmal in einer "csv-Datei". Das ist nicht schön. Deswegen solltest Du besser das gewünschte Tabellenblatt in eine neues Workbook kopieren - und dieses dann abspeichern. Dann umgehst Du das Problem, dass Du den Ast, auf dem Du sitzt, absägst.

                                              Zweitens: Ja, Du hast wenig Einfluß auf die Speicherung und gerade die Abhängigkeit von den Ländereinstellungen kann gewaltig nerven.

                                              Das ist mir einmal in einem Access-Projekt passiert, dort hatte ich Formulare dynamisch generiert und angepasst. Ich musste alles auf Twips umstellen, um nie, nie, nie in Zeichenketten mit Kommazahlen arbeiten zu müssen. War lehrreich.

                                              Interessant ist, dass Excel durchaus korrekte CSV-Dateien erzeugt, diese allerdings selbst nicht richtig einlesen kann (getestet mit Excel 2007)

                                              Ach ja, noch was: CSV-Dateien solltest Du in Excel _nicht_ über "Datei öffnen" oder das Kontextmenü der Datei öffnen. Nein, Du solltest in einer Arbeitsmappe über Daten -> Importieren gehen. Dann kannst Du einige Parameter festlegen.

                                              Mit Zeilenumbrüchen in Inhalten kommt Excel jedoch nicht klar.

                                              Freundliche Grüße

                                              Vinzenz

                                              1. Hellihello Vinzenz,

                                                Zweitens: Ja, Du hast wenig Einfluß auf die Speicherung und gerade die Abhängigkeit von den Ländereinstellungen kann gewaltig nerven.

                                                Das ist mir einmal in einem Access-Projekt passiert, dort hatte ich Formulare dynamisch generiert und angepasst. Ich musste alles auf Twips umstellen, um nie, nie, nie in Zeichenketten mit Kommazahlen arbeiten zu müssen. War lehrreich.

                                                Interessant ist, dass Excel durchaus korrekte CSV-Dateien erzeugt, diese allerdings selbst nicht richtig einlesen kann (getestet mit Excel 2007)

                                                Genau das fiel mir auch auf. Immerhin unterscheidet sich die SaveAs Methode abhängig davon, ob sie aus dem Marko/VBA oder übers Menü aufgerufen wird (einmal mit Kommas, kann Excel nicht lesen auf anhieb, einmal mit Semikolon).

                                                Ach ja, noch was: CSV-Dateien solltest Du in Excel _nicht_ über "Datei öffnen" oder das Kontextmenü der Datei öffnen. Nein, Du solltest in einer Arbeitsmappe über Daten -> Importieren gehen. Dann kannst Du einige Parameter festlegen.

                                                Nun ja, Excel hat die Daten ja, ist ja die Datenbasis.

                                                Mit Zeilenumbrüchen in Inhalten kommt Excel jedoch nicht klar.

                                                Kann ich nicht bestätigen. Meins kann das hier lesen:

                                                  
                                                title1;titel2;titel3  
                                                """A2""";";B2;";"C2¶&chr(11)&aaa       Zelle_as_CSV = check_convert_and_wrap(Zelleninhalt)  
                                                            Debug.Print (Spaltennummer & ""-"")  
                                                            Debug.Print Zelle_as_CSV"  
                                                A3;B3;C3  
                                                
                                                

                                                Mein CSV-ersteller (erstmal ohne Abspeichern und Aufruf einer Batchdatei zum Hochladen auf einen Server) sieht momentan so aus:

                                                  
                                                'Variablendeklaration verplichtend durch  
                                                Option Explicit  
                                                ' Indiziere Arrays von 1 an, matched zum Zähler da unten ab 1  
                                                Option Base 1  
                                                  
                                                'Globale Vars deklarieren (s.a. Funktion Wrapper)  
                                                'die Zuweisung durch chr() geht scheints nur im Sub  
                                                'eigentlich wäre das eine Const, aber das klappt durch die chr()-Zuweisung nicht  
                                                Dim Semikolon, CRLF, Anführungszeichen As String  
                                                  
                                                Sub my_csv()  
                                                    CRLF = Chr(13) & Chr(10)  
                                                    Anführungszeichen = Chr(34)  
                                                    Semikolon = Chr(59)  
                                                  
                                                    'Declaration  
                                                    Dim UrsprungsZeile, UrsprungsSpalte  As Object  
                                                    Dim Zeilenanzahl, Spaltenanzahl, Zeilennummer, Spaltennummer As Integer  
                                                  
                                                    'Arrays  
                                                    Dim Zeilen() As String  
                                                    Dim Spalten() As String  
                                                  
                                                    Dim Zelleninhalt, Zelle_as_CSV, Zeile_as_CSV, Tabelle_as_CSV As String  
                                                  
                                                    'Rows- and Columns.Count for Use in Redimension of Arrays below  
                                                    Zeilenanzahl = ActiveSheet.UsedRange.Rows.Count  
                                                    Spaltenanzahl = ActiveSheet.UsedRange.Columns.Count  
                                                  
                                                    'Redimension des Arrays  
                                                    ReDim Zeilen(Zeilenanzahl) As String  
                                                    ReDim Spalten(Spaltenanzahl) As String  
                                                  
                                                    'initialize Ausgabestring  
                                                    Tabelle_as_CSV = ""  
                                                  
                                                    'so, nun geh mal durch die Zeilen  
                                                    For Zeilennummer = 1 To Zeilenanzahl Step 1  
                                                        'Zeile als String initialiiseren  
                                                        Zeile_as_CSV = ""  
                                                        'so, nun geh mal durch die Spalten in der Zeile  
                                                        For Spaltennummer = 1 To Spaltenanzahl Step 1  
                                                            'hohl dir den Inhalt der Zelle, als *.value, weil mind. eine Zelle mehr als 1024 Zeichen haben kann  
                                                            Zelleninhalt = ActiveSheet.UsedRange.Rows(Zeilennummer).Cells(Spaltennummer).Value  
                                                            'lass den Wrapper ran  
                                                            Zelle_as_CSV = check_convert_and_wrap(Zelleninhalt)  
                                                            'stopf es ins Spaltenarray  
                                                            Spalten(Spaltennummer) = Zelle_as_CSV  
                                                        Next  
                                                        'Spaltenarray in String mit Semikolon als Seperator zerlegen und ins Zeilenarray stopfen  
                                                        Zeilen(Zeilennummer) = Join(Spalten, Semikolon)  
                                                        'sollte hier das Spaltenarray geleert werden und wenn ja wie?  
                                                    Next  
                                                    'Zeilenarray in String mit CRLF als Seperator zerlegen - thats it  
                                                    Tabelle_as_CSV = Join(Zeilen, CRLF)  
                                                    Debug.Print Tabelle_as_CSV  
                                                End Sub  
                                                  
                                                  
                                                Function check_convert_and_wrap(Zelleninhalt)  
                                                    'Soll ich nun wrappen?  
                                                    Dim wrap As Boolean  
                                                    wrap = False  
                                                  
                                                   'checked, ob Anführungszeichen im Zelleninhalt  
                                                    If InStr(Zelleninhalt, Anführungszeichen) > 0 Then  
                                                        'dann bitte 1. wrappen  
                                                        wrap = True  
                                                        '2. die Anführungszeichen im Zelleninhalt jeweils verdoppeln  
                                                        Zelleninhalt = Replace(Zelleninhalt, Anführungszeichen, Anführungszeichen & Anführungszeichen)  
                                                  
                                                    'wenn keine Anführungszeichen, dann schauen, ob Semikolon oder Absatzmarke (CR&LF)  
                                                    ElseIf (InStr(Zelleninhalt, Semikolon) > 0 Or InStr(Zelleninhalt, CRLF) > 0) Then  
                                                        'wenn ja, dann wrappen  
                                                        wrap = True  
                                                        Debug.Print (Zelleninhalt & "aaaaaa")  
                                                    End If  
                                                    'wenn wrappen  
                                                    If wrap Then  
                                                        'dann setz die Rückgabe in Anführungszeichen  
                                                        check_convert_and_wrap = Anführungszeichen & Zelleninhalt & Anführungszeichen  
                                                    Else  
                                                        'ansonsten bleibt alles, wies ist und wird dennoch zurückgegeben  
                                                        check_convert_and_wrap = Zelleninhalt  
                                                    End If  
                                                End Function  
                                                
                                                

                                                Ich hab das ganze ja jetzt so angepackt deinem Rat folgend, ein Standardformat lieber für Character-Delimited-Values zu nehmen, wobei ich nach wie vor mit den o.g. Problemen und der Frage YAGNI überlege, ob String-Delimited-Values nicht doch auch eine (proprietäre) Alternative wären.

                                                Zudem möchte ich eigentlich im Folgeschritt vergleichen, welche Zeilen sich geändert haben. Mit PHP würde ich also jedes Zeilenarray eigentlich wieder Zerlegen mittels implode() und den String dann vergleichen mit der bisherigen Zeile. Sind sie gleich, ist kein update nötig. Das würde bei String-Demlimited-Values ein implode() sparen (;-).

                                                Abgesehen würde ich das ganze gern portieren auf OpenOffice. StarBasic aber scheint etwas anders zu sein. So finde ich kein Debug.Print sondern nur Print und das öffnet immer eine kleine OK-Box. Auch fehlt mir der Bezeichner für "ActiveSheet" und "UsedRange" zB. Schön finde ich aber, dass hier auch Javascript oder Python nutzbar wäre. Hast Du damit Erfahrung? Vielleicht mach ich mal einen neuen Thread dazu, hier in den verschachtelten Tiefen scheints mir, sind wir beide grad allein.

                                                Zu guter letzt sinniere ich auch über das Konzept, das auf den Server hochzuladen. Mit einem "ftp -s:ftp-script" hab ich schon einen Ansatz. Aber dann weiß der Server ja immer noch nicht, dass er die neue Datenbasis vergleichen und einarbeiten solle.

                                                Rufe ich ein *.htm-Dokument auf, dann muss der User selbst die Datei zum Hochladen bestimmen, was lästig wäre. Nähme ich ein *.hta, könnte ich die Lösung nicht 1:1 auf Linux übertragen. Auch in neuem Thread vielleicht.

                                                DankDank und GrußGruß,

                                                frankx