Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi UTF8ToAnsi (gemodded) und ANSI/UTF8 gemischt (https://www.delphipraxis.net/43533-utf8toansi-gemodded-und-ansi-utf8-gemischt.html)

sECuRE 5. Apr 2005 14:14


UTF8ToAnsi (gemodded) und ANSI/UTF8 gemischt
 
Hi,

ich hab kürzlich die Funktion UTF8ToAnsi gefunden und wenn in dem String nur UTF8-Zeichen oder "standard" vorkommen, funktioniert alles. Kommen allerdings "normale" Sonderzeichen (ISO-Irgendwas-Zeichensatz), also äöüß vor, bricht die Funktion ab und hinterlässt einen leeren String - nicht grade schön. Ich hab deshalb die Funktion etwas umgeschrieben:
Delphi-Quellcode:
// Das Copyright dieser Funktion liegt bei Borland, ich hab lediglich 4 Zeilen an verschiedenen Stellen ergänzt. Die Funktion findet man in der System.pas wenn man eine Delphi-Version mit Sourcecode der VCL hat.
function _Utf8ToUnicode(Dest: PWideChar; MaxDestChars: Cardinal; Source: PChar; SourceBytes: Cardinal): Cardinal; overload;
var
  i, count: Cardinal;
  c: Byte;
  wc: Cardinal;
begin
  if Source = nil then
  begin
    Result := 0;
    Exit;
  end;
  Result := Cardinal(-1);
  count := 0;
  i := 0;
  if Dest <> nil then
  begin
    while (i < SourceBytes) and (count < MaxDestChars) do
    begin
      wc := Cardinal(Source[i]);
      Inc(i);
      if (wc and $80) <> 0 then
      begin
        if i >= SourceBytes then begin
          dest[count]:=widechar(source[i-1]); // von mir eingefügt, normal stand hier "exit;"
          Inc(count);
          continue;
        end;         // incomplete multibyte char
        wc := wc and $3F;
        if (wc and $20) <> 0 then
        begin
          c := Byte(Source[i]);
          Inc(i);
          if (c and $C0) <> $80 then begin
            dest[count]:=WideChar(source[i-2]); // von mir eingefügt, normal stand hier "exit;"
            Inc(count);
            Dec(i);
            continue;
          end;     // malformed trail byte or out of range char
          if i >= SourceBytes then begin
            dest[count]:=WideChar(source[i-2]); // von mir eingefügt, normal stand hier "exit;"
            Inc(count);
            continue;
          end;       // incomplete multibyte char
          wc := (wc shl 6) or (c and $3F);
        end;
        c := Byte(Source[i]);
        Inc(i);
        if (c and $C0) <> $80 then begin
        dest[count]:=widechar(source[i-2]); // von mir eingefügt, normal stand hier "exit;"
        Inc(count);
        Dec(i); continue; end;      // malformed trail byte

        Dest[count] := WideChar((wc shl 6) or (c and $3F));
      end
      else
        Dest[count] := WideChar(wc);
      Inc(count);
    end;
    if count >= MaxDestChars then count := MaxDestChars-1;
    Dest[count] := #0;
  end
  else
  begin
    while (i < SourceBytes) do
    begin
      c := Byte(Source[i]);
      Inc(i);
      if (c and $80) <> 0 then
      begin
        if i >= SourceBytes then exit;         // incomplete multibyte char
        c := c and $3F;
        if (c and $20) <> 0 then
        begin
          c := Byte(Source[i]);
          Inc(i);
          if (c and $C0) <> $80 then exit;     // malformed trail byte or out of range char
          if i >= SourceBytes then exit;       // incomplete multibyte char
        end;
        c := Byte(Source[i]);
        Inc(i);
        if (c and $C0) <> $80 then exit;      // malformed trail byte
      end;
      Inc(count);
    end;
  end;
  Result := count+1;
end;
Nach verschiedenen AND/OR-Verknüpfungen wird also abgebrochen, diese Abbrüche hab ich einfach blind ersetzt und es funktioniert. Dass die Lösung nicht sehr schön ist, ist mir klar. Mit anderen Umlauten außer öäüß hab ich die Funktion bisher nicht getestet.

Meine Frage nun: Wozu sind die ganzen AND/OR-Verknüpfungen da, was wird da überprüft? Und: Wie kann man meine Lösung verbessern? Gibt es da schon Funktionen, mit denen man "gemischte" Strings vereinheitlichen kann?

BTW: (Zum testen) UTF8-"ö": ö

Vielen Dank & cu

himitsu 7. Apr 2005 13:36

Re: UTF8ToAnsi (gemodded) und ANSI/UTF8 gemischt
 
Hab ich das jetzt richtig verstanden ???

Du hast einem UTF8-String direkt ein Sonderzeichen (z.B. das ö) untergeschoben und diesen "defekten" UTF8-String dann an UTF8toAnsi übergeben, worauf dieser Funktion dann natürlich abgestürtzt ist?

Delphi-Quellcode:
Var S: String;
  D: PWideChar;

S := 'ö';

Utf8ToUnicode(D, 1, PChar(S), 1);

Na kein Wunder, dass diese Funktion so reageirte ... schau dir lieber mal das Format eines UTF8-Strings an ... ein UTF8String ist kein AnsiString :warn:

sECuRE 7. Apr 2005 14:23

Re: UTF8ToAnsi (gemodded) und ANSI/UTF8 gemischt
 
Hi,

also ich hab's so gemacht:
Delphi-Quellcode:
function ConvertString(S:string):string;
begin
result:=UTF8ToAnsi(S);
end;

// ...
ConvertedString:=ConvertString('test'); // funktioniert
ConvertedString:=ConvertString('ö'); // funktioniert (UTF8)
ConvertedString:=ConvertString('test äöü'); // funktioniert NICHT :(
Daraufhin hab ich die Funktion wie oben "gepatcht". Das funktioniert dann.

Meintest du das so? Oder ist der Aufruf wie ich ihn gemacht hab doch richtig?

Danke & cu

Bernhard Geyer 7. Apr 2005 14:31

Re: UTF8ToAnsi (gemodded) und ANSI/UTF8 gemischt
 
Zitat:

Zitat von sECuRE
Daraufhin hab ich die Funktion wie oben "gepatcht". Das funktioniert dann.

Meintest du das so? Oder ist der Aufruf wie ich ihn gemacht hab doch richtig?

Danke & cu

Ich würde ihn lieber so machen. UTF8ToAnsi sollte nur das machen für was es bestimmt ist und Nicht-UTF8 bzw. gemischte Strings wandeln. Entweder UTF8-String oder keiner.

Delphi-Quellcode:
function ConvertString(S:string):string;
begin
result:=UTF8ToAnsi(S); // Delphi-Orginal-Funktion
if result = '' then // String leer, wenn kein UTF8 -> Orginal Zurückliefern
  result := S;
end;

himitsu 7. Apr 2005 14:35

Re: UTF8ToAnsi (gemodded) und ANSI/UTF8 gemischt
 
Genau das meinte ich und genau das ist der Fehler.

ÄÖÜ ist Ansi und nicht UTF8 ... also kannst du das nur andersrum machen AnsiToUTF8.

sECuRE 7. Apr 2005 14:56

Re: UTF8ToAnsi (gemodded) und ANSI/UTF8 gemischt
 
Hi,

OK - wie überprüf ich denn nun, ob irgendwo Ansi im String vorkommt (bewusst auch Zeichen außer äöü) und wie verhalte ich mich in der Situation richtig, in der ich sowohl UTF8 als auch Ansi parsen will?

Danke & cu

himitsu 7. Apr 2005 15:16

Re: UTF8ToAnsi (gemodded) und ANSI/UTF8 gemischt
 
Du mußt schon selber wissen, oder der String ein Ansi, UTF, oder sonst irgendein Stringformat hat und dementspechend mußt du dann auch die Funktionen auswählen


Bei Delphi ist ist z.B. der UTF8String indern auch nunr als eine Ableitung des AnsiStrings definiert, wodurch daher keine Programmseitige Unterscheidung möglich ist.

Ansi/Wide/UTF8/UTF16/UTF32.... das sind alles Stringformatierungsvarianten, dass heißt, das die alle die Zeichen in einem anderem Format speichern.

sECuRE 7. Apr 2005 15:36

Re: UTF8ToAnsi (gemodded) und ANSI/UTF8 gemischt
 
Hi,

naja prinzipiell hab ich immer das selbe Stringformat. Ich les den Text von einem Indy-Clientsocket, gesendet wird der vom IRC-Server. Was der IRC-Client nun reinschreibt auf der Gegenseite bleibt ihm überlassen - meistens ANSI, im Falle von XChat halt standardmäßig UTF-8.

Die Zeichen werden also alle gleich gespeichert würd ich sagen, deshalb möcht ich ja die UTF8-Zeichen da "rauskonvertieren".

Danke & cu

Bernhard Geyer 7. Apr 2005 15:42

Re: UTF8ToAnsi (gemodded) und ANSI/UTF8 gemischt
 
Zitat:

Zitat von sECuRE
naja prinzipiell hab ich immer das selbe Stringformat. Ich les den Text von einem Indy-Clientsocket, gesendet wird der vom IRC-Server. Was der IRC-Client nun reinschreibt auf der Gegenseite bleibt ihm überlassen - meistens ANSI, im Falle von XChat halt standardmäßig UTF-8.

Normalerweise wird bei Internet-Protokollen noch irgendwo die verwendet Codierung (z.B. UTF8) mitgeliefert.
D.h. dein Ansatz würde schon scheitern, wenn nicht UTF8 bzw. 1252-1 verwendet wird.
Da ich Indy nicht verwende weiß ich nicht wo du dort nachschauen mußt.

himitsu 7. Apr 2005 16:08

Re: UTF8ToAnsi (gemodded) und ANSI/UTF8 gemischt
 
Nachtrag:
Im Grundegenommen kannst du deine "umgebaute" Prozedur wegschmeißen ... da sie ja jetzt Fehlerhaft ist.


Aber wenn du nicht nachschauen kannst, was genau ankommen, also ob mal Ansi oder UTF ankommt, kannst du ja einen "nicht" so ganz guten Weg versuchen.

Wie gesagt, perfekt ist das nicht.
Es wird halt versucht den String von UTF8 nach Ansi umzuwandeln
und bei einem Fehler, also wenn der String kein UTF8-String ist, dann wird er als AnsiString verwendet.
Delphi-Quellcode:
SIn := ... // die empfangenen Daten

Try
  // von UTF8 nach ANSI umwandeln
  SOut := UTF8ToAnsi(SIn);
Except
  // und bei Fehler die Daten so übernehmen
  SOut := SIn;
End;

// SOut enthält jetzt (vermutlich) die Daten im ANSI-Format
Also versuche lieber rauszubekommtn was ankommt und dann dementsprechend diese Daten dann zu verwenden.
Delphi-Quellcode:
S := {empfangene Daten}
If {Datenformat der empfangenen Daten = UTF8} Then
  S := UTF8ToAnsi(S);

// Hier hätte man dann S im ANSI-Format (wenn nur ANSI und UTF8 möglich ist)
PS: in delphi wird standardmäßig das ANSI-Format verwendet,
weßhalb derzeit der String und der AnsiString genau das Selbe darstellen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:18 Uhr.
Seite 1 von 2  1 2      

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-2025 by Thomas Breitkreuz