Delphi-PRAXiS
Seite 2 von 2     12   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   WideStringlist in UTF-8 mit Delphi 2007 speichern (https://www.delphipraxis.net/213634-widestringlist-utf-8-mit-delphi-2007-speichern.html)

Uwe Raabe 31. Aug 2023 14:42

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;

himitsu 31. Aug 2023 15:35

AW: WideStringlist in UTF-8 mit Delphi 2007 speichern
 
Wie gesagt, Arrayzugriffe auf leere Strings/Arrays, knallen gern mal, daher
Delphi-Quellcode:
if Zeile <> '' then
  Stream.WriteBuffer(Zeile[1], Length(Zeile)*Sizeof(WideChar));

// oder

Stream.WriteBuffer(PWideChar(Zeile)^, Length(Zeile)*Sizeof(WideChar));
Wenn man das BOM vorher als CHAR in den String einfügt, ist es egal, da dann der String nie leer ist.




PS: die TWideStrings und TWideStringList der Unit Delphi-Referenz durchsuchenWideStrings speichern auch das BOM.
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;

ioster 31. Aug 2023 15:47

AW: WideStringlist in UTF-8 mit Delphi 2007 speichern
 
Zitat:

Zitat von himitsu (Beitrag 1526325)
Wie gesagt, Arrayzugriffe auf leere Strings/Arrays, knallen gern mal, daher
Delphi-Quellcode:
if Zeile <> '' then
  Stream.WriteBuffer(Zeile[1], Length(Zeile)*Sizeof(WideChar));

// oder

Stream.WriteBuffer(PWideChar(Zeile)^, Length(Zeile)*Sizeof(WideChar));
Wenn man das BOM vorher als CHAR in den String einfügt, ist es egal, da dann der String nie leer ist.




PS: die TWideStrings und TWideStringList der Unit [OH]WideStrings[OH] speichern auch das BOM.
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;

In Delphi 2007 ist das offenbar nicht der Fall. Die originäre Routine von CodeGear hatte ich eingangs als Delphi-Quellcode eingefügt. Der fehlende BOM verursachte für mich erst das Problem, weil der Konverter ohne dem die Dateiinhalte nicht lesen konnte.

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

ioster 31. Aug 2023 15:49

AW: WideStringlist in UTF-8 mit Delphi 2007 speichern
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1526318)
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;

DANKE!!!! Das hat geholfen, wobei ich das inhaltlich immer noch nicht verstehe. Doch ich kann das Programm nun wieder in Kombination mit dem Konverter einsetzen ohne manuell per Editor den Dateiinhalt mit einer anderen Codierung abspeichern zu müssen.

Viele Grüße
Ingo

himitsu 31. Aug 2023 16:22

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


https://www.compart.com/de/unicode/U+FEFF
https://de.wikipedia.org/wiki/Byte_Order_Mark

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:

mytbo 31. Aug 2023 16:28

AW: WideStringlist in UTF-8 mit Delphi 2007 speichern
 
Wenn umfangreicher mit UTF-8 gearbeitet wird, kannst du ab Delphi 7 mORMot verwenden. Ist der Eingang ein WideString, dann mit WideStringToUtf8 konvertieren:
Delphi-Quellcode:
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;
Ansonsten den String-Typ RawUtf8 verwenden. Mit den Funktionen StringToUtf8/Utf8ToString diesen Typ in allen Delphi Versionen konvertieren.

Bis bald...
Thomas

himitsu 31. Aug 2023 16:43

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 22:40 Uhr.
Seite 2 von 2     12   

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz