Encoding-Unklarheiten beim CSV-Export für Excel

Mit welcher Methode (a) und mit welchem Encoding (b) muss ich eine CSV-Datei aus Xojo exportieren, wenn ich nach dem Öffnen in Excel (Win und Mac) die Umlaute korrekt sehen will?

Aktueller Stand: Egal, was ich mache, die Umlaute erscheinen mach dem Import in Excel immer in zwei kryptischen Symbolen aufgesplittet, wahrscheinlich ist das falsch interpretiertes UTF8.

zu a) stellt sich mir die Frage ob mit TextOutputStream oder mit BinaryStream? Habe im Web beide Beispiele gefunden, macht in meinem Falle aber beim Ergebnis keinen Unerschied

zu b) habe UTF8 und WindowsAnsi …

Dim output As TextOutputStream

Dim i,j As Integer
Dim buf As String
Dim cx As String = ";"
Dim gf As String = Chr(34)

If file=Nil Then Return
output = TextOutputStream.create(file)

If source.hasHeading Then
  For i=0 To source.columnCount-1
    buf = source.heading(i)
    buf = buf.DefineEncoding(Encodings.utf8)
    output.Encoding = Encodings.utf8
    output.write gf+buf+gf+cx
  next
  output.write chr(13)
end if

for i=0 to source.listcount-1
  for j=0 to source.columncount-1
    buf = source.cell(i,j)
    buf = buf.DefineEncoding(Encodings.utf8)
    output.Encoding = Encodings.utf8
    output.write gf+buf+gf+cx
  next
  output.write chr(13)
next
output.close

Das ist die von mir modifizierte Export-Routine aus der “ExcelWritterExtension By Alex Restrepo” …

Danke für Tips.

Nachtrag: Mir ist klar, dass man das Problem mit extra Einstellungen beim Import (statt “Öffnen”) in Excel lösen kann. Das Gefummel möchte ich aber dem User nicht zumuten, der soll einfach Doppelklicken und … fertig.

ein Teil hat eine Kodierung, der Rest nicht…

PS: Es gibt: output.writeline

y Sie sprechen von csv, aber Sie verwenden ‘;’ und Kegeln … aber es scheint für Sie zu funktionieren.

Moin,
ich würde zunächst den kompletten String in einem weiteren String zusammenbauen, dem dann die Codierung nochmal explizit zuweisen, und dann über output.writeline (wie Emil schon schrieb) ausgeben. Das verhindert Codierungs-Mischmasch. Auch kannst Du dann im Debugger vor dem Schreiben des Strings kontrollieren, ob die Codierung stimmt.

1 Like

“y Sie sprechen von csv, aber Sie verwenden ‘;’ und Kegeln … aber es scheint für Sie zu funktionieren.”

Ja, Excel hat ganz eigene Vorstellungen von CSV … hier die Daten in verschiedenen Ansichten, erzeugt und als CSV aus Excel für Mac exportiert

Hier die Ansicht in einem Hex-Editor:

Bildschirmfoto 2023-04-02 um 11.21.17

die Ansicht in Excel selbst:

die Ansicht in Visual Studio Code:

Ja und so?
Wie viele Bytes sollen sie in UTF-8 aufnehmen?

Das mit den 5 Bytes war wohl ein Irrtum, das sieht nur in der ersten Zelle so aus, hab eich gerade geändert.

UTF-8 belegt m.W. für Nicht-Umlaute 8Bit (deshalb UTF-8) und für Umlaute 1 Umschaltcode und 1 Code für das Zeichen …

Der Umschalt-Code scheint C3 zu sein … ist wohl doch UTF-8 … ok, ich teste die oben empfohlenen Änderungen (String etc.)

image
für:
Dim foo As String = “äëïöüÿ ÄËÏÖÜŸ ñÑ”

Diese akzentuierten Vokale wurden in der IDE / Xojo 2021r2.1 / Ventura eingegeben.

Ich habe kein Excel (seit Anfang der 1990er Jahre nicht mehr verwendet …)

Kurzer Ausflug zum Thema Trennzeichen in csv: auch wenn im Namen von “Comma” die Rede ist, sind auch Semikolon, Doppelpunkt, Tabulator oder Leerzeichen gebräuchliche Trennzeichen (siehe: csv (Dateiformat))

Wenn es für die späteren Anwender möglichst einfach sein soll die Daten in Excel zu öffnen, dann würde ich sie gleich im .xslx Format ausgeben. Dafür gibt es ja mehrere Möglichkeiten, neben den beiden kommerziellen Plugins (von MBS und Einhugur) gibt es eine Variante via Javascript (siehe Blog von Tim Dietrich) und ältere Xojo-only Lösungen…

1 Like

Kannst du mir bitte eine solche ältere Xojo-only-Lösung nennen? Danke.

Da reicht eine Forumssuche, so bin ich auch darauf gestossen - der Thread ist allerdings achon 10 Jahre alt, keine Ahnung ob die Links noch funktionieren: RBLibrary: ExcelWriter - #28 by Simon_Berridge

Falls du bei der .csv-Lösung bleiben willst:

  • stelle sicher, dass du eine BOM hast.
  • ich bin mir nicht sicher bezüglich der Zeile buf = buf.DefineEncoding(Encodings.utf8). Die Zelle sollte bereits einen Text-String enthalten (einen String mit einer Encoding) damit in der Oberfläche alles passt. Das umzudefinieren, ist nicht sinnvoll. Wenn, dann musste es ConvertEncoding sein, aber das ist unnötig, da der TextOutputStream als UTF-8-Stream definiert ist und Xojo demnach von selbst konvertiert.

Um eine BOM zu erhalten schreibst du als erstes in die Datei:

output.Write encodings.UTF8.Chr(&hFEFF)

Das sollte dann die ersten 3 Bytes von deinem Hexdump oben ergeben.

Und noch etwas anderes, was verwirrend sein kann, wenn du zwischen Mac und Windows hin und her wechselst:

Die Umlaute kann man in Unicode in zwei Formen schreiben: pre-composed und de-composed. Windows verwendet standardmäßig die erste Form, Mac oft die zweite.
Als pre-composed ist das ü ein Codepoint: &uFC, codiert in UTF-8: &hC3, &hBC.
Als de-composed besteht das ü aus dem Zeichen u gefolgt von einem Zeichen “kombinierende Dieresis”, dem Ü-Zeichen das über das u gestellt wird: &u6F, &u0308. in UTF-8 &h75, &hCC, &h88

Super, Treffer! Danke!
Der Hinweis mit der BOM (byte order mark) war genau das Richtige! Ohne BOM kann man Ecodings setzen, bis man schwarz wird, Excel interessiert sich einen Sch… dafür. Der nachfolgende Code liefert CSVs, die ohne jede Nachfrage sofort in Excel geöffnet werden und die Umlaute stimmen, sowohl unter MacOS als auch Windows (“source” ist eine Listbox!).

Uff … Projekt gerettet :slight_smile:

Dim output As textoutputStream
Dim i,j As Integer
Dim buf As String
Dim cx As String = ";"

If file=Nil Then Return

For i=0 To 128
  If file.Exists Then file.Delete
Next

output = TextOutputStream.create(file)
output.Encoding = Encodings.utf8
output.Write encodings.UTF8.Chr(&hFEFF)

If source.hasHeading Then
  For i=0 To source.columnCount-1
    buf = ource.heading(i) + cx
    buf = buf.DefineEncoding(encodings.ASCII)
    output.write buf
  Next
  output.write Chr(13)
End If

For i=0 To source.listcount-1
  For j=0 To source.columncount-1
    buf = source.cell(i,j) + cx
    buf = buf.DefineEncoding(Encodings.ascii)
    output.write buf
  Next
  output.write Chr(13)
Next
output.close

file.launch

Sollten die Zellen das Zeichen “;” enthalten, müssen sie zusätzlich in " " gesetzt werden, ansonsten kann man auch darauf verzichten.

1 Like