Delphi-PRAXiS
Seite 4 von 4   « Erste     234

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Mal wieder Kodierungsprobleme. ANSI UTF8 UTF16 (https://www.delphipraxis.net/194418-mal-wieder-kodierungsprobleme-ansi-utf8-utf16.html)

LTE5 18. Nov 2017 11:49

AW: Mal wieder Kodierungsprobleme. ANSI UTF8 UTF16
 
Danke für die Erklärung.

Könnte haarig werden. Ich verwende hier und dort TFile.AppendAllText. Hier kann ich ja einfach TEncoding.Unicode dranhängen.
Wie ich es beim LESEN mache (TFile.ReadAllText), muss ich noch gucken. Vielleicht eine kleine INterposer-Klasse für TFile oder so, wo ich dann im überschriebenem ReadAllText das Encoding prüfe.. Mal gucken

Habe nun diese drei Proceduren/Funktionen in meine Shared-Utils-Sammlung aufgenommen. Bei Bedarf erweiterbar. Das hier ist erst der Anfang und soll nur eine zentrale Stelle Bilden, wo sich der Code zum Schreiben/Lesen befindet. Muss ich etwas ändern, ist es nur an einer Stelle und nicht an 100.
Bisher funktioniert alles einwandfrei. UTF-16 LE wird problemlos geschrieben und gelesen.

Delphi-Quellcode:
class procedure TFileUtils.FileAppendText(const Path, Contents: string; const Encoding: TEncoding);
begin
 TFile.AppendAllText(Path, Contents, Encoding);
end;

class procedure TFileUtils.FileWriteText(const Path, Contents: string; const Encoding: TEncoding);
begin
 TFile.WriteAllText(Path, Contents, Encoding);
end;

class function TFileUtils.FileGetTextReadAllText(const Path: string; const Encoding: TEncoding): string;
begin
 Result := TFile.ReadAllText(Path, Encoding);
end;
Ich habe nun nach ein paar Stunden alles nach Unicode umgestellt. Alle Daten, egal wo im Programm, werden korrekt geschrieben und gelesen.
Lediglich da wo ich zu 100% weiß, dass niemals etwas anderes als a-z und 0-9 gespeichert wird, schreibe und lese ich trotzdem noch im utf-8-Format.
Ich nutze UTF-16 aus einem einfachen Grund: wird eine Datei gelesen, die nicht UTF-16 ist, gibt es keine Fehlermeldung.

LTE5 18. Nov 2017 16:28

AW: Mal wieder Kodierungsprobleme. ANSI UTF8 UTF16
 
Folgender Artikel hat mir die Augen geöffnet. Ist ein bisschen was zu lesen. Aber es ließt sich zum Glück einfacher als andere englische Texte

The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)

Ich verwende nun UTF-8.

mensch72 18. Nov 2017 17:45

AW: Mal wieder Kodierungsprobleme. ANSI UTF8 UTF16
 
..."Ich verwende nun UTF-8."...
keine schlechte Entscheidung, viele "alte" C/C++-Programmierer mit dem Dogma "ein String" ist und bleibt ein ByteArray sind diesen Weg gegangen!
->aber akzeptiere mit Delphi XE10.x das du nun überall ausser bei WebSeiten dich selbst stets beim Einlesen und Ausgeben und ALLEN WinApi Funktionen um die paassende Konvertierung kümmern musst, bzw immer prüfen ob die implizite Typkonvertierung von Delphi noch/schon richtig arbeitet.
Denn leider ist "draussen" und in allen SYSTEM-APIs wenn UTF, dann UTF-16 verbreitet. Aber Kopfhoch, Lazerus/FreePascal schafft das ja auch, denn die arbeiten intern mit UTF8 und da gibt es von PC,Linux,Mac,Android,IOS,Rasperry,... "alles".
Wenn du mal in Delphi mit UTF8 nicht weiter kommst, sieh eventuell mal in die Sourcen der LCL wie die das dort an der vergleichbaren Stelle machen.

Ich arbeite intern auch mit UTF8. Da ich eh durchgehend mit Getter&Setter Funktionen für "string" Propertys arbeite ist das relativ problemlos. Man muss nur bei UTF8 beachten, das man als ZeichenAnzahl nicht simpel die Byteanzahl nimmt, weil diese ja eben oft nicht mit der realen Zeichenanzahl übereinstimmt... daher ist eine "eigene" Funktion ala "CharCount(utf8String)" gleich von Anfang an eine der wichtigsten Funktionen sie man sicher "einmal richtig" selbst schreiben(und verstehen) sollte.

Wenn ich in meinen Programmen mit "CharCount" arbeite, geht es fast immer um Positionierung oder visuelle Begrenzungen.
Wenn ich in meinen Programmen mit "Length" oder "StrLen" arbeite geht es bei mir weiter um Speicherplatz und echtes Lesen&Schreiben von "Bytes".

;)Ich hoffe ich habe dir hiermit nicht die "Lust" auf eigenes interes UTF8 verdorben.... aber 98% der aktuellen Delphi&Windowsprogrammier nehmen ja nicht zufällig lieber UTF-16, bzw. wissen garnicht das sie intern mit UTF-16 arbeiten;)

LTE5 18. Nov 2017 17:53

AW: Mal wieder Kodierungsprobleme. ANSI UTF8 UTF16
 
Zitat:

Ich arbeite intern auch mit UTF8. Da ich eh durchgehend mit Getter&Setter Funktionen für "string" Propertys arbeite ist das relativ problemlos. Man muss nur bei UTF8 beachten, das man als ZeichenAnzahl nicht simpel die Byteanzahl nimmt, weil diese ja eben oft nicht mit der realen Zeichenanzahl übereinstimmt... daher ist eine "eigene" Funktion ala "CharCount(utf8String)" gleich von Anfang an eine der wichtigsten Funktionen sie man sicher "einmal richtig" selbst schreiben(und verstehen) sollte.
Ich gucke einfach ob Fehler auftreten und erst dann ändere ich was. Richtig verstanden habe ich das eh nicht und dieses Byte-geschupse mit Streams... davon halte ich mich eh fern ;)

Ich arbeite mit strings, nicht mit utf8strings.

p80286 18. Nov 2017 21:12

AW: Mal wieder Kodierungsprobleme. ANSI UTF8 UTF16
 
Wenn Du in Deiner Datei den Wert x90 findest, dann kann dieser für NOP stehen, ist sicher, daß an dieser Position Buchstaben zu finden sind, dann könnte es das Zeichen É sein (Extended ASCII) oder das zweite Byte in einer UTF8-Sequenz. Oder anders ausgedrückt es handelt sich nicht um eine ANSI-Kodierung. (Ich hoffe ich habe da recht).
Die Kodierung gibt an in welches Zeichen ein Wert bzw. eine Wertfolge übersetzt wird.

Unter diesen Bedingungen wirst Du nur dann eine Fehlermeldung bekommen, wenn eine Kodierung dekodiert werden soll, die nicht zulässig ist (im Rahmen der gewählten Kodierung).

Gruß
K-H

LTE5 18. Nov 2017 21:28

AW: Mal wieder Kodierungsprobleme. ANSI UTF8 UTF16
 
Es gibt noch das hier aber wie man das anwendet ist mir ein Rätsel.
http://chsdet.sourceforge.net/

Sonst habe ich noch das hier gefunden, bin aber gerade unfähig eine ansi-Datei zu erstellen. Daher bekomme ich bei jeder Datei true zurück
Delphi-Quellcode:
function FileMayBeUTF8(FileName: WideString): Boolean;
var
 Stream: TMemoryStream;
 BytesRead: Integer;
 ArrayBuff: array [0 .. 127] of Byte;
 PreviousByte: Byte;
 i: Integer;
 YesSequences, NoSequences: Integer;

begin
 if not FileExists(FileName) then
  Exit;

 YesSequences := 0;
 NoSequences := 0;
 Stream := TMemoryStream.Create;
 try
  Stream.LoadFromFile(FileName);
  repeat

   {read from the TMemoryStream}

   BytesRead := Stream.Read(ArrayBuff, High(ArrayBuff) + 1);
   {Do the work on the bytes in the buffer}
   if BytesRead > 1 then
    begin
     for i := 1 to BytesRead - 1 do
      begin
       PreviousByte := ArrayBuff[i - 1];
       if ((ArrayBuff[i] and $C0) = $80) then
        begin
         if ((PreviousByte and $C0) = $C0) then
          begin
           inc(YesSequences)
          end
         else
          begin
           if ((PreviousByte and $80) = $0) then
            inc(NoSequences);
          end;
        end;
      end;
    end;
  until (BytesRead < (High(ArrayBuff) + 1));
  // Below, >= makes ASCII files = UTF-8, which is no problem.
  // Simple > would catch only UTF-8;
  Result := (YesSequences >= NoSequences);

 finally
  Stream.Free;
 end;
end;
Hier noch eine schöne Version. Gibt aber leider bei ANSI auch true zurück
Delphi-Quellcode:
function UTF8CharLength(const c: Byte): Integer;
begin
 // First Byte: 0xxxxxxx
 if ((c and $80) = $00) then
  begin
   Result := 1;
  end
  // First Byte: 110yyyyy
 else if ((c and $E0) = $C0) then
  begin
   Result := 2;
  end
  // First Byte: 1110zzzz
 else if ((c and $F0) = $E0) then
  begin
   Result := 3;
  end
  // First Byte: 11110uuu
 else if ((c and $F8) = $F0) then
  begin
   Result := 4;
  end
  // not valid, return the error value
 else
  begin
   Result := -1;
  end;
end;

function UTF8IsTrailChar(const c: Byte): Boolean;
begin
 // trail bytes have this form: 10xxxxxx
 Result := ((c and $C0) = $80);
end;

function IsUTF8Memory(AMem: PBYTE; ASize: Int64): Boolean;
var
 i: Int64;
 c: Integer;
begin
 Result := True;
 i := 0;
 while (i < ASize) do
  begin
   // get the length if the current UTF-8 character
   c := UTF8CharLength(AMem^);
   // check if it is valid and fits into ASize
   if ((c >= 1) and (c <= 4) and ((i + c - 1) < ASize)) then
    begin
     Inc(i, c);
     Inc(AMem);
     // if it is a multi-byte character, check the trail bytes
     while (c > 1) do
      begin
       if (not UTF8IsTrailChar(AMem^)) then
        begin
         Result := False;
         Break;
        end
       else
        begin
         Dec(c);
         Inc(AMem);
        end;
      end;
    end
   else
    begin
     Result := False;
    end;
   if (not Result) then
    Break;
  end;
end;

LTE5 18. Nov 2017 23:10

AW: Mal wieder Kodierungsprobleme. ANSI UTF8 UTF16
 
Ich habe mich an der ganzen Sache nun mal versucht. Schöner bekomme ich es leider nicht hin

Delphi-Quellcode:
function ByteToHex(AByte: Byte): string;
const
 Digits: array [0 .. 15] of char = '0123456789ABCDEF';
begin
 Result := Digits[AByte shr 4] + Digits[AByte and $0F];
end;

function BytesToHex(ABytes: TBytes): string;
var
 i: Integer;
begin
 for i := 0 to High(ABytes) do
  Result := Result + ByteToHex(ABytes[i]);
end;

function GetFileEncoding(const FileName: string): string;
var
 Stream: TBytesStream;
 Bytes: TBytes;
begin
 Stream := TBytesStream.Create;

 try
  Stream.LoadFromFile(FileName);

  if Stream.Size >= 3 then
   begin
    SetLength(Bytes, 3);
    Stream.ReadData(Bytes, 3);
   end
  else if Stream.Size >= 2 then
   begin
    SetLength(Bytes, 2);
    Stream.ReadData(Bytes, 2);
   end;

  if BytesToHex(Bytes) = 'EFBBBF' then
   ShowMessage('UTF-8 BOM')
  else if BytesToHex(Bytes) = 'FEFF' then
   ShowMessage('UTF-16 BE');

 finally
  Stream.Free;
 end;
end;
Ich hätte auch noch das hier im Angebot:
Delphi-Quellcode:
function IsTextUnicode(const Text: string): Boolean;
var
 C: Char;
begin
 Result := False;

 for C in Text do
  begin
   if C > #127 then
    begin
     Result := True;
     Break;
    end;
  end;
end;

function IsFileUnicode(const AFile: string): Boolean;
var
 i: Int64;
 Stream: TBytesStream;
begin
 Result := False;

 Stream := TBytesStream.Create;
 try
  Stream.LoadFromFile(AFile);

  for i := 0 to Stream.Size - 1 do
   begin
    if Char(Stream.Bytes[i]) > #127 then
     begin
      Result := True;
      Break;
     end;
   end;
 finally
  Stream.Free;
 end;
end;

freimatz 20. Nov 2017 11:12

AW: Mal wieder Kodierungsprobleme. ANSI UTF8 UTF16
 
Zitat:

Zitat von mensch72 (Beitrag 1386578)
;)Ich hoffe ich habe dir hiermit nicht die "Lust" auf eigenes interes UTF8 verdorben.... aber 98% der aktuellen Delphi&Windowsprogrammier nehmen ja nicht zufällig lieber UTF-16, bzw. wissen garnicht das sie intern mit UTF-16 arbeiten;)

Warum sollte man intern mit UTF8 arbeiten? Der Vorteil hat sich mir noch nicht erschlossen. Ich selber nehme intern das Delphi übliche UTF-16. Nach außen wandele ich dann was gerade dran ist wei z.B. ANSI oder UTF-8. Intern muss ich noch teilweise noch Hand anlegen wgen altem Code und weil die Unterstützung von Delphi für Surrogaten recht bescheiden ist.


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:31 Uhr.
Seite 4 von 4   « Erste     234

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