![]() |
WideStringlist in UTF-8 mit Delphi 2007 speichern
Moin,
ich habe eine Anwendung, die Textzeilen nach einem vorgegebenen Format in einer Stringlist sammelt und dann in einer Textdatei wegschreibt, die von einem Konverter zur Weiterverarbeitung abgegriffen wird. Nun stand eine Änderung an, weil in den Strings Zeichen aus dem erweiterten Zeichensatz verarbeitet werden sollten. Konkret geht es um slowakische Sonderzeichen. Deswegen musste ich die Routinen auf Widestrings und eine Widestringlist umbauen. Funktioniert inzwischen so weit auch wunderbar, ABER der Konverter streikt, da die neuen Textdateien in UTF-16-LE und nicht mehr in UTF-8 codiert werden. Ich nutze zur Speicherung die Methode SaveToFile, die leider keine Optionen in Sachen Codierung bietet. Anhand der Sourcen konnte ich auch nur ermitteln, dass beim Aufruf der Methode ein FileStream zur Speicherung genutzt wird.
Delphi-Quellcode:
Ich gehe davon aus, dass die UTF-Codierung irgendwo an einer anderen Stelle festgelegt ist.
procedure TWideStrings.SaveToFile(const Filename: WideString);
var Stream: TStream; begin Stream := TFileStream.Create(Filename, fmCreate); try SaveToStream(Stream); finally Stream.Free; end; procedure TWideStrings.SaveToStream(Stream: TStream); var S: WideString; begin S := GetTextStr; Stream.WriteBuffer(Pointer(S)^, Length(S) * SizeOf(WideChar)); end; Hat jemand eine Idee, wie ich mit einer ähnlichen Funktion die Codierung des Outputs selber steuern kann? Alles was ich gefunden habe, passte nicht zu Delphi 2007. Danke im Voraus. Ingo |
AW: WideStringlist in UTF-8 mit Delphi 2007 speichern
Wenn UTF-8, dann kann das auch eine normale TStringList (nur das BOM, falls nötig, mußt du einfach als erstes Zeichen in die erste Zeile einfügen).
![]() aber hier geht auch ![]() oder eine der vielen UTF8-Konvertierungs-Funktionen aus der System.pas PS: Der ![]() |
AW: WideStringlist in UTF-8 mit Delphi 2007 speichern
Moin,
ich kann in dem Projekt nur auf die Möglichkeiten von Delphi 2007 zurückgreifen. Anhand von Foreneinträgen und technischen Tipps habe ich schon festgestellt, dass sich der Hersteller inzwischen einiges mehr zu dem Thema einfallen lassen hat. Eine TStringlist habe ich bisher genutzt. Doch damit komme ich nicht weiter, wenn ich den erweiterten Zeichensatz verarbeiten möchte. Den kann ich nur mit WideStrings auslesen und ich wurde auch schon gerüffelt, als ich bei den Kollegen nachfragte, warum denn die Sonderzeichen bei der Zuweisung in die TStringlist wieder verschwinden würden. Daran merkt man, dass ich bisher mit den WideStrings in der Form nichts zu tun hatte. Jetzt habe ich gestern versucht, die WideStringliste Zeile für Zeile mit einem Filestream abzuspeichern, habe dabei aber nichts Brauchbares erzeugen können. Wenn ich die Textdatei mit einem Editor öffne, bekomme ich Sonderzeichen aus dem südostasiatischen Raum angezeigt - vermutlich chinesisch. Ich möchte zusätzlich auch den BOM mitgeben, weil es der Konverterhersteller sich so wünscht. Aus Codebeispielen habe ich versucht, mir eine eigene Prozedur zusammenzustellen, die so aussieht:
Delphi-Quellcode:
Ich fürchte nur, dass ich ein Problem bei der Umwandlung oder bei der Positionierung des Streams habe.
procedure SaveToUTF16(const Filename: string; Content: TWidestringlist);
var BOM : WideChar; Stream : TFileStream; Zaehler : integer; Zeile : WideString; begin Stream := TFileStream.Create(Filename, fmCreate); try BOM := WideChar($FFFE); Stream.WriteBuffer(BOM, SizeOf(BOM)); FOR Zaehler := 0 to Content.Count - 1 Do begin Zeile := WideString(Content[Zaehler] + sLineBreak); Stream.WriteBuffer(PWideChar(Zeile)^, Length(Zeile) * SizeOf(WideChar)); end; finally Stream.Free; end; Es hat schon seinen Grund, warum ich sonst gerne auf bestehende Methoden wie SaveToFile zurückgreife. Danke im Voraus. Viele Grüße Ingo |
AW: WideStringlist in UTF-8 mit Delphi 2007 speichern
Zitat:
|
AW: WideStringlist in UTF-8 mit Delphi 2007 speichern
In deinem Code speicherst du aber UTF-16 anstatt UTF-8. Ist das denn so gewollt?
Zitat:
Delphi-Quellcode:
uses
WideStrings, WideStrUtils; procedure SaveToUTF8(const Filename: string; Content: TWideStrings); var Stream : TFileStream; Zeile : UTF8String; begin Zeile := UTF8Encode(Content.Text); Stream := TFileStream.Create(Filename, fmCreate); try Stream.WriteBuffer(sUTF8BOMString[1], Length(sUTF8BOMString)); Stream.WriteBuffer(Zeile[1], Length(Zeile)); finally Stream.Free; end; end; |
AW: WideStringlist in UTF-8 mit Delphi 2007 speichern
Liste der Anhänge anzeigen (Anzahl: 2)
Zitat:
Anhang 56212 Darüber habe ich auch den Unterschied zwischen den Textdateien aus Stringlist und WideStringlist feststellen können. Mit einem Hex-Editor gehe ich an so etwas nicht heran. Speichere ich nun Textzeilen mit der oben aufgeführten Routine, dann wird als Codierung UTF-16-BE angezeigt, doch der Dateiinhalt ist alles andere als lesbar. Anhang 56213 Nach meinem Verständnis müsste dort trotzdem Klartext erkennbar sein. |
AW: WideStringlist in UTF-8 mit Delphi 2007 speichern
Zitat:
Viele Grüße Ingo |
AW: WideStringlist in UTF-8 mit Delphi 2007 speichern
Zitat:
Was müsste ich denn jetzt ändern, um UTF16 ausgeben zu können. Die Konvertierung entfällt dann ja. Grundsätzlich dürfte sich das Verfahren ja nicht unterscheiden, oder? Viele Grüße Ingo |
AW: WideStringlist in UTF-8 mit Delphi 2007 speichern
Ich bin irgendwie zu blöd, um zu kapieren, wie man den BOM in eine UTF-16-Datei geschrieben bekommt.
Nun habe ich die UTF8-Lösung und habe auf dem CodeGear-Quellcode basierend das für den Fall der Fälle das für UTF-16 umsetzen wollen. Sobald ich den BOM wegschreibe, kommt in der Datei nichts Vernünftiges an. Es dürfte doch jetzt eigentlich nur noch um eine Zeile gehen.
Delphi-Quellcode:
Muss ich bei WriteBuffer mit Length oder SizeOf arbeiten und wie muss ich den BOM bearbeiten?
BOM := WideChar($FFFE);
Stream.WriteBuffer(BOM, SizeOf(BOM)); |
AW: WideStringlist in UTF-8 mit Delphi 2007 speichern
Jupp, das #$FEFF ist das Unicode-BOM.
Es wird in der jeweiligen Codepage gespeichert. (wenn sie es darstellen kann) Am Einfachsten als Char/WideChar an den Anfang des Textes. BOM geht z.B. beim UTF-16-LE, UTF-16-BE und UTF-8. (ja, die 3 UTF8-Bytes sind jenes Char)
Delphi-Quellcode:
Hach, wie schön doch ein
Zeile := UTF8Encode(#$FEFF + Content.Text);
Stream := TFileStream.Create(Filename, fmCreate); try //Stream.WriteBuffer(sUTF8BOMString[1], Length(sUTF8BOMString)); Stream.WriteBuffer(Zeile[1], Length(Zeile)); // natürlich würde @Zeile[1] knallen, wenn der String leer ist finally Stream.Free; end; ![]() |
AW: WideStringlist in UTF-8 mit Delphi 2007 speichern
Delphi-Quellcode:
procedure SaveToUTF16(const Filename: string; Content: TWideStrings);
var BOM: TBytes; Stream : TFileStream; Zeile : WideString; begin Zeile := Content.Text; Stream := TFileStream.Create(Filename, fmCreate); try BOM := TBytes.Create($FF, $FE); Stream.WriteBuffer(BOM[0], Length(BOM)); Stream.WriteBuffer(Zeile[1], Length(Zeile)*Sizeof(Zeile[1])); finally Stream.Free; end; end; |
AW: WideStringlist in UTF-8 mit Delphi 2007 speichern
Wie gesagt, Arrayzugriffe auf leere Strings/Arrays, knallen gern mal, daher
Delphi-Quellcode:
Wenn man das BOM vorher als CHAR in den String einfügt, ist es egal, da dann der String nie leer ist.
if Zeile <> '' then
Stream.WriteBuffer(Zeile[1], Length(Zeile)*Sizeof(WideChar)); // oder Stream.WriteBuffer(PWideChar(Zeile)^, Length(Zeile)*Sizeof(WideChar)); PS: die TWideStrings und TWideStringList der Unit ![]() Weiß nicht ob und wie vor Delphi XE das gemacht wurde, aber diese Unit gab es auch schon in Delphi 7, wenn ich mich nicht total irre.
Delphi-Quellcode:
procedure TWideStrings.SaveToStream(Stream: TStream; Encoding: TEncoding);
var Buffer, Preamble: TBytes; begin if Encoding = nil then Encoding := TEncoding.Unicode; // The default encoding is UTF-16 Buffer := Encoding.GetBytes(string(GetTextStr)); Preamble := Encoding.GetPreamble; if Length(Preamble) > 0 then Stream.WriteBuffer(Preamble[0], Length(Preamble)); Stream.WriteBuffer(Buffer[0], Length(Buffer)); end; |
AW: WideStringlist in UTF-8 mit Delphi 2007 speichern
Zitat:
Dein Quellcode mit der UTF8-Umwandlung habe ich nicht verstanden. Als Ergebnis kam bei mir eine ANSI-Datei heraus, deren Zeichen mit einem Leerzeichen voneinander getrennt waren. Die Lösung ist jetzt aber dank Uwe Raabe da. Der Ansatz funktioniert, wobei ich immer noch nicht durchblicke, wann mit SizeOf, Length etc. gearbeitet werden muss. Ich hatte mir etliche Beispiele angeschaut, die sich aber meistens auf neuere Delphi-Versionen bezogen und somit nicht 1:1 umzusetzen waren. Viele Grüße Ingo |
AW: WideStringlist in UTF-8 mit Delphi 2007 speichern
Zitat:
Viele Grüße Ingo |
AW: WideStringlist in UTF-8 mit Delphi 2007 speichern
der eizige Unterschied ist
* man kann das codierte BOM und anschließend den codierten Text in den Stream/Datei schreiben * man kann aber auch das uncodierte BOM in den Text einfügen und das dann zusammen codiert in den Stream/Datei schreiben #$FFFF ist ungültig/verboten (laut Unicode-Standard) #$FFFE ist ungültig/verboten, aber wird als Char für den ByteOrderMark verwendet #$FEFF ist ungültig/verboten, wegen Konflikt mit dem ByteOrderMark und der Bereich #$Fxxxxxxx ist sowieso nicht existent (somit kein Konflikt möglich) Folgendes sind BOM, welche alle dem Char #$FFFF entsprechen, jeweils in ihrer Codepage dargestellt. EF BB BF = UTF-8 FE FF = UTF-16 (sowie auch UCS2), jeweils BigEndian und LittleEndian (kleinstes oder größtes Byte der Chars zuerst) FF FE 00 00 FE FF = UTF-32, jeweils BigEndian und LittleEndian FF FE 00 00 ![]() ![]() Achtung $FF $FE ist $FEFF und nicht $FFFE Windows ist LittleEndian (nicht so wie Apple früher mal BigEndian) und in Dateien wird oft auch LittleEdnian gespeichert (also praktischer Weise sind somit Datei und RAM gleich) -> zuerst das kleinste Byte -> beim Dezimal und HEX aber die Ziffern der einzelnen Bytes wiederum BigEndian :lol: Größere mehrstellige "Zahlen" sind aber BigEndian, im Text/Quellcode -> zuerst die größte Ziffer Im HTML/CSS sind Farbwerte aber andersrum, also LittleEndian, gegen über TColor -> #RRGGBB vs. $BBGGRR :wall: |
AW: WideStringlist in UTF-8 mit Delphi 2007 speichern
Wenn umfangreicher mit UTF-8 gearbeitet wird, kannst du ab Delphi 7
![]()
Delphi-Quellcode:
Ansonsten den String-Typ RawUtf8 verwenden. Mit den Funktionen StringToUtf8/Utf8ToString diesen Typ in allen Delphi Versionen konvertieren.
type
mormot.core.data, mormot.core.unicode; var line: WideString; list: TRawUtf8List; begin list := TRawUtf8List.Create; try line := '...'; list.Add(WideStringToUtf8(line)); list.SaveToFile('test.txt'); // write all lines into a new UTF-8 file finally list.Free; end; Bis bald... Thomas |
AW: WideStringlist in UTF-8 mit Delphi 2007 speichern
Eine Delphi-Vesion weiter (2009) war Unicode/UTF-8 dann auch nativ besser nutzbar. :duck:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:05 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz