WideString, AnsiString, UTF8String, UCS4String Verwirrung

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
RSE
Beiträge: 462
Registriert: Mi 30. Jul 2008, 13:11
OS, Lazarus, FPC: WinXP SP3 (L 0.9.28.2 FPC 2.2.4)
CPU-Target: 32Bit
Kontaktdaten:

Re: WideString, AnsiString, UTF8String, UCS4String Verwirrung

Beitrag von RSE »

Wie ist das mit dem Dateizugriff/ der Übergabe von Pfaden? Ich (Laz 0.9.26 auf WinXP) bekomme offenbar vom OpenDlg UTF8. FindFirst benötigt offenbar Ansi. Kann ich davon ausgehen, dass alle Schnittstellen zum System (zumindest im Fall von WinXP) Ansi verlangen bzw. liefern? Bis jetzt ist das so (TOpenDialog ist ja nicht Systemeigen), habe schon mehrere Stellen probiert (z.b. application.exename und findfirst). Ich hoffe das ist wenigstens eingheitlich so. Speziell bin ich jetzt mal auf readXMLFile und WriteXMLFile gespannt, die arbeiten intern mit TFileStream hab ich schon gesehen. 2.: Wie verhält sich das dann auf anderen Systemen, wie z.B. Linux? Sind da beim Crosscompiling Compilerweichen nötig?
Seit er seinen neuen Computer hat, löst er alle Probleme, die er vorher nicht hatte!

Benutzeravatar
theo
Beiträge: 10871
Registriert: Mo 11. Sep 2006, 19:01

Re: WideString, AnsiString, UTF8String, UCS4String Verwirrung

Beitrag von theo »

http://wiki.lazarus.freepascal.org/LCL_ ... _filenames" onclick="window.open(this.href);return false;

RSE
Beiträge: 462
Registriert: Mi 30. Jul 2008, 13:11
OS, Lazarus, FPC: WinXP SP3 (L 0.9.28.2 FPC 2.2.4)
CPU-Target: 32Bit
Kontaktdaten:

Re: WideString, AnsiString, UTF8String, UCS4String Verwirrung

Beitrag von RSE »

Ups, danke für den Link, sehr interessant. Ist aber sicherlich gut, dass dieser Link in diesem Thread mit erscheint ;-)
Seit er seinen neuen Computer hat, löst er alle Probleme, die er vorher nicht hatte!

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: WideString, AnsiString, UTF8String, UCS4String Verwirrung

Beitrag von mse »

RSE hat geschrieben:Wie ist das mit dem Dateizugriff/ der Übergabe von Pfaden??
Bei MSEide+MSEgui ist das so gelöst, dass alle File Dialoge und dergleichen mit widestrings arbeiten. Für das Öffnen von Dateien und Erstellen von streams gibt es MSEgui eigene, widestring basierte Funktionen und Klassen, die Umsetzung in die vom Betriebssystem benötigte Codierung wird von MSEgui vorgenommen. Es gibt auch eine Plattform unabhängige Form der Pfadnamen, "c:\aaa\bbb\ccc.ddd" wird zu "/c:/aaa/bbb/ccc.ddd".
Die MSEgui Datenbank Komponenten konvertieren Text beim Lesen von utf-8 oder der Systemcodierung (einstellbar) zu widestring. In den MSEgui Datenpuffern werden Texte als widestrings variabler Länge gehalten. Beim Schreiben der Texte zur Datenbank wird wieder zu utf-8 oder der Systemcodierung gewandelt.

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: WideString, AnsiString, UTF8String, UCS4String Verwirrung

Beitrag von mschnell »

mse hat geschrieben:Der Unterschied ist halt, dass bei utf-8 durch die Begrenzung auf ASCII lediglich Amerikaner die effiziente Adressierung mittels Index benutzen können, bei utf-16 durch UCS2 praktisch alle Erdenbürger, die Europäer auf jeden Fall. ;-)
Woher soll denn das system wissen ob da gerade kein Chinese vor dem Bildschirm sitzt ? Wenn Surrogate Pairs erlaubt sind, muss _immer_ durchsucht werden, statt einen Index zu benutzen. Schau Dir doch 'mal den ASM code an der bei a:widechar; s: widestring; a := s; erzeugt wird (bei MSEIDE geht das ja, bei Lazarus leider nicht).
mse hat geschrieben:Ebenfalls zu bedenken ist, dass Surrogate*pair* handling wesentlich einfacher und effizienter zu implementieren ist als die Behandlung der 1 bis 4 Bytes von utf-8.
das ist wohl wahr. Trotzdem ist ein Widechar nur 16 bit und da passt kein surrogate pair rein.

-Michael
Zuletzt geändert von mschnell am So 19. Okt 2008, 22:36, insgesamt 1-mal geändert.

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: WideString, AnsiString, UTF8String, UCS4String Verwirrung

Beitrag von mschnell »

theo hat geschrieben:Du kannst dich einfach auf den Standpunkt stellen, dass bei dir keine Zeichen über $FFFF vorkommen, dann hast du damit auch nix zu tun und kannst deine WideString als UCS-2 betrachten.
Das ist sicher wahr. Wenn die Widestrings aber nicht richtig mit surrogats funktionieren weil z.B. Widechar (16 Bit) keine surrogates aufnehmen kann und wenn man mit "x[3]:=irgendwas;" auch x[4] verändert, weil ein surrogate da hingeschrieben wird, das sowohl x[3] als auch x[4] belegt, gibt dann aber keinen vernünftigen Grund die Widestring/WideChar -Kodierung als utf16 zu bezeichnen und nicht als ucs2.
-Michael

Benutzeravatar
theo
Beiträge: 10871
Registriert: Mo 11. Sep 2006, 19:01

Re: WideString, AnsiString, UTF8String, UCS4String Verwirrung

Beitrag von theo »

mschnell hat geschrieben: Das ist sicher wahr. Wenn die Widestrings aber nicht richtig mit surrogats funktionieren weil z.B. Widechar (16 Bit) keine surrogates aufnehmen kann und wenn man mit "x[3]:=irgendwas;" auch x[4] verändert, weil ein surrogate da hingeschrieben wird, das sowohl x[3] als auch x[4] belegt, gibt dann aber keinen vernünftigen Grund die Widestring/WideChar -Kodierung als utf16 zu bezeichnen und nicht als ucs2.
Ich kann dir nicht ganz folgen. Ein Widechar kann nat. nicht ein Surrogat-Paar speichern.
Aber was willst du damit sagen?

RSE
Beiträge: 462
Registriert: Mi 30. Jul 2008, 13:11
OS, Lazarus, FPC: WinXP SP3 (L 0.9.28.2 FPC 2.2.4)
CPU-Target: 32Bit
Kontaktdaten:

Re: WideString, AnsiString, UTF8String, UCS4String Verwirrung

Beitrag von RSE »

Wenn du string[4] einen 2 WideChar breites Surrogat Paar zuweist, wird das an Position 4 und 5 geschrieben. Damit hast du Zeichen 5 u.U. ungewollt überschrieben. Ist halt nur alles nicht mehr so einfach wie zu ANSI-Zeiten ;-)
Seit er seinen neuen Computer hat, löst er alle Probleme, die er vorher nicht hatte!

Benutzeravatar
theo
Beiträge: 10871
Registriert: Mo 11. Sep 2006, 19:01

Re: WideString, AnsiString, UTF8String, UCS4String Verwirrung

Beitrag von theo »

Ich hab mal einen Versuch gemacht (GTK2) mit Zeichen über $FFFF:
Was ist hier falsch? Ich bekomme eine 0 Länge für den WideString und UTF8String;

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
var
   UCS4S:UCS4String;
   WS:WideString;
   UTF8S:UTF8String;
begin
  SetLength(UCS4S,1);
  UCS4S[1]:=UCS4Char($100E4);   //LINEAR B IDEOGRAM VESSEL B205. UTF8 Sequenz: f0 90 83 a4
  writeln(Length(UCS4S)); //-> 1
 
  WS:=UCS4StringToWideString(UCS4S);
  writeln(Length(WS)); //-> 0
 
  UTF8S:=UTF8Encode(WS);
  writeln(Length(UTF8S)); //-> 0
 
  Caption:=UTF8S; // -> ''
end;

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: WideString, AnsiString, UTF8String, UCS4String Verwirrung

Beitrag von mse »

theo hat geschrieben: Was ist hier falsch?
UCS4String ist null basierend:

Code: Alles auswählen

 
  UCS4Char            = type 0..$10ffff;
  PUCS4Char           = ^UCS4Char;
  TUCS4CharArray      = array[0..$effffff] of UCS4Char;
  PUCS4CharArray      = ^TUCS4CharArray;
  UCS4String          = array of UCS4Char;
 
UCS4StringToWideString erwartet ein terminating null:

Code: Alles auswählen

 
function UCS4StringToWideString(const s : UCS4String) : WideString;
  var
    i        : SizeInt;
    resindex : SizeInt;
  begin
    { skip terminating #0 }
    SetLength(result,length(s)-1);
    resindex:=1;
    for i:=0 to high(s)-1 do
      ConcatUTF32ToWideStr(s[i],result,resindex);
    { adjust result length (may be too big due to growing }
    { for surrogate pairs)                                }
    setlength(result,resindex-1);
  end;
 
Also:

Code: Alles auswählen

 
  SetLength(UCS4S,1+1);         //one char + terminating 0
  UCS4S[0]:=UCS4Char($100E4);   //LINEAR B IDEOGRAM VESSEL B205. UTF8 Sequenz: f0 90 83 a4
                                //UCS4String is 0 based
  writeln(Length(UCS4S)); //-> 2
 
  WS:=UCS4StringToWideString(UCS4S);
  writeln(Length(WS));    //-> 2
 
  UTF8S:=UTF8Encode(WS);
  writeln(Length(UTF8S)); //-> 6 ????
 
und so ganz koscher scheint UTF8Encode auch nicht zu sein (FPC fixes_2_2)...
Vermutlich hat tatsächlich noch kein FPC Anwender Codepoints ausserhalb UCS2 verwendet.

Benutzeravatar
theo
Beiträge: 10871
Registriert: Mo 11. Sep 2006, 19:01

Re: WideString, AnsiString, UTF8String, UCS4String Verwirrung

Beitrag von theo »

mse hat geschrieben: UCS4String ist null basierend:
Autsch, hätte ich sehen müssen. Merci!
So geht's: Siehe UTF16ToUTF8(WS) statt UTF8Encode

Code: Alles auswählen

procedure TForm1.Button3Click(Sender: TObject);
var
   UCS4S:UCS4String;
   WS:WideString;
   UTF8S:UTF8String;
   i:integer;
begin
  SetLength(UCS4S,1+1);
  UCS4S[0]:=UCS4Char($100E4);   //LINEAR B IDEOGRAM VESSEL B205. UTF8 Sequenz: f0 90 83 a4
  writeln(Length(UCS4S));
 
  WS:=UCS4StringToWideString(UCS4S);
  writeln(Length(WS));
 
  UTF8S:=UTF16ToUTF8(WS);
  writeln(Length(UTF8S));
 
  Caption:=UTF8S;
  for i:=1 to Length(UTF8S) do Write(' $'+IntToHex(Byte(UTF8S[i]),2)); //-> $F0 $90 $83 $A4
end;

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: WideString, AnsiString, UTF8String, UCS4String Verwirrung

Beitrag von mse »

mschnell hat geschrieben: das ist wohl wahr. Trotzdem ist ein Widechar nur 16 bit und da passt kein surrogate pair rein.
Schon, aber für viele Aufgaben hat utf-16 trotzdem Vorteile gegenüber utf-8.
Nimm mal an, du willst das erste Vorkommen des Zeichen 'Ä' oder jedes andern UCS2 Zeichens in einem String herausfinden. Mit widestrings geht das zum Beispiel so:

Code: Alles auswählen

 
var
 wstr1: widestring;
 wch1: widechar;
 po1,po2,po3: pwidechar;
 result: ptruint;
begin
              //#nnn notation because of encoding independent example
 wstr1:= '12345'#196'7890';  
 wch1:= #196;
 po1:= pwidechar(wstr1);
 po2:= po1;
 po3:= po1;        //base pointer backup
 while po1^ <> #0 do begin
  if po1^ = wch1 then begin
   po2:= po1+1;
   break;
  end;
  inc(po1);
 end;
 result:= po2-po3; //found char pointer - basepointer + 1 -> stringindex
 writeln(result);  // 6
    //zero in case of not found
end.
 
Mit utf-8 wäre dies nur in Amerika möglich, da Codepoints > 127 nicht in eine utf-8 Einheit passen.

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: WideString, AnsiString, UTF8String, UCS4String Verwirrung

Beitrag von mschnell »

RSE hat geschrieben:Wenn du string[4] einen 2 WideChar breites Surrogat Paar zuweist, wird das an Position 4 und 5 geschrieben. Damit hast du Zeichen 5 u.U. ungewollt überschrieben. Ist halt nur alles nicht mehr so einfach wie zu ANSI-Zeiten ;-)
Wie soll es denn überhaupt gehen, s[4] ein Surrogat Paar zuzuweisen ?

-Michael

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: WideString, AnsiString, UTF8String, UCS4String Verwirrung

Beitrag von mschnell »

RSE hat geschrieben:Ich kann dir nicht ganz folgen. Ein Widechar kann nat. nicht ein Surrogat-Paar speichern. Aber was willst du damit sagen?
Damit will ich sagen, dass WideChar nicht utf16 kodiert sein kann, weil ein utf16 Character aus einem Surrogat-Paar (also 32 Bit) bestehen kann.
Widechar ist also offensichtlich UCS2 kodiert. Für mich repräsentiert ein Widestring eine Kette von Widechars und ist deshalb auch UCS2-kodiert und nicht utf16.

-Michael

Benutzeravatar
theo
Beiträge: 10871
Registriert: Mo 11. Sep 2006, 19:01

Re: WideString, AnsiString, UTF8String, UCS4String Verwirrung

Beitrag von theo »

mschnell hat geschrieben: Damit will ich sagen, dass WideChar nicht utf16 kodiert sein kann, weil ein utf16 Character aus einem Surrogat-Paar (also 32 Bit) bestehen kann.
Widechar ist also offensichtlich UCS2 kodiert. Für mich repräsentiert ein Widestring eine Kette von Widechars und ist deshalb auch UCS2-kodiert und nicht utf16.
Naja, kann man so sehen. Aber das Problem ist genau das gleiche wie bei ANSI und UTF8. Gewisse Chars in UTF8 sind vollständige Zeichen, andere nur Teil eines Codes / einer Sequenz.

Das was du "haben willst" ist UCS-4. Da geht alles, frisst aber Speicher.

Antworten