uppercase und lowercase

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Benutzeravatar
theo
Beiträge: 10949
Registriert: Mo 11. Sep 2006, 19:01

Re: uppercase und lowercase

Beitrag von theo »

mschnell hat geschrieben:Die Frage, warum wideuppercase bei Widestrings und AnsiUppercase bei Ansistrins nicht mit Umlauten funktioniert, steht immer noch im Raum.
Mache ich was falsch oder ist das ein Bug ? (wie gesagt: bei Turbo-Delphi macht derselbe code das, was ich erwarte).
Bei mir funzen beide Varianten, WideString und UTF8. Hab aber nur auf GTK2 getestet:
(Beispiel ohne -Fcutf8 als Compilerparameter)

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
begin
Caption:=UTF8UpperCase('gähn')+UTF8Encode(WideUppercase(UTF8Decode('gähn')));
end;

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: uppercase und lowercase

Beitrag von mschnell »

Christian hat geschrieben:Ich komm nicht wirklich mit, a := b sollte doch immer den gesamten string kopieren oder ?
Nö !
In Delphi und sicherlich auch in Free-Pascal passiert bei Strings ein "lazy-yopy". Wenn man einen String in eine andere Variable "kopiert", wird nur der Pointer kopiert (und der Referenmz-zähler erhöht). Erst wenn ein String verändert wird, wird der Inhalt (das Array der Zeichen) kopiert. Da Strings in sehr vielen Fällen nie verändert werden, sondern meist z.B- der Variable ein komplett neu erstellter String zugewiesen wird, ist das eine sehr effektive Methodik. (In .NET Umgebungen ist das Verändern eines Strings überhaupt nicht möglich, was bei der Portierung von Pascal-Programmen mit "Delphi for .NET" oder "Oxygene" einige Arbeit machen kann.)
Der Programmierer merkt nichts davon, weil die RTL das im Hintegrund managt, sieht es für ihn so aus als würde der String bei der Zuweisung komplett kopiert (wie z.B. ein Integer. Referenz-Counting ist da natürlich die Voraussetzung. Im Gegensatz ist bei dynamic Arrays (die ja in mancher Beziehung so ähnlich wie Strings sind), eine Zuweisung explizit eine Pointer-Operation (wie bei Klassen): wird das Arrays über eine Variablen, der es zugewiesen wurde, verändert, spiegelt sich die Änderung in allen Variablen wieder.

Code: Alles auswählen

 
var
  a1, a2: array of char;
  s1, s2: AnsiString;
 
begin
  setlength(a,2);
  a1[0] := 'A';
  a1[1] := 'B';
 
  s1 := 'AB';  
 
  a2 := a1;    // Pointer wird kopiert
  s2 := s1;    // Pointer  wird kopiert und Referenz-Zähler wird erhöht: "lazy copy"
 
  a2[1] := 'C'; // char wird ersetzt
  s2[1] := 'C'; // neuer String wird angelegt, Daten copy, Referenzzähler von s1 wird dekrementiert und dann wird char ersetzt
 
// nun ist a1 = 'A' 'C' und s1 immer noch = 'AB'
 
Christian hat geschrieben:Und wann verarbeitet man megabyteweise Daten in strings ?
Warum nicht ? Ist doch genauso legitim, wie die Daten in anderen Strukturen zu halten. Je nach Anwendung ist natürlich die eine oder andere Datenstruktur besser geeignet.

-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: uppercase und lowercase

Beitrag von mschnell »

mse hat geschrieben:Unter Windows ist dies leider eine Tatsache, vielleicht kannst du dich noch an mein Gezeter auf fpc-devel erinnern.
In Linux nicht ?!?!?!
Die Frage, warum wideuppercase bei Widestrings und AnsiUppercase bei Ansistrins nicht mit Umlauten funktioniert, steht immer noch im Raum.
Ich nehme an, dass Du unter Windows mit utf-8 codierter Pascal Datei arbeitest. Für AnsiUpper/Lowercase ist es klar, die strings werden an das Betriebssystem weitergeleitet welches die Systemcodierung erwartet, dies ist unter Windows höchstwahrscheinlich nicht utf-8.
Mit widestrings sollte es funktionieren, hast du -Fcutf8 als Compilerparameter angegeben?
Verstehe ich nicht. Was hat die Kodierung der Quell-Dateien damit zu tun ? Sie Strings haben den richtigen Typ und vor dem Aufruf der passenden uppcase() den richtigen Inhalt. Nach uppercase() sind die ASCII-Zeichen konvertiert, die Umlaute nicht.
Was hat das mit utf8 zu tun? (Auf utf8-Strings will ich ja erstmal gar nicht eingehen.). Meine tests sind mit Widestrings (anscheinend ucs2 Kodierung, jedenfalls 16 bit pro character) und mit ANSI-Strings ("lokale"-abhängige ANSI-Kodierung, jedenfalls genau 8 bit pro Zeichen, keine utf-Erweiterung). Das sollten die entsprechenden Funktionen dich in jedem Fall korrekt verarbeiten können !!
-Michael
Zuletzt geändert von mschnell am Sa 18. Okt 2008, 13:57, 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: uppercase und lowercase

Beitrag von mschnell »

theo hat geschrieben:
mschnell hat geschrieben:Die Frage, warum wideuppercase bei Widestrings und AnsiUppercase bei Ansistrins nicht mit Umlauten funktioniert, steht immer noch im Raum.
Mache ich was falsch oder ist das ein Bug ? (wie gesagt: bei Turbo-Delphi macht derselbe code das, was ich erwarte).
Bei mir funzen beide Varianten, WideString und UTF8. Hab aber nur auf GTK2 getestet:
(Beispiel ohne -Fcutf8 als Compilerparameter)

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
begin
Caption:=UTF8UpperCase('gähn')+UTF8Encode(WideUppercase(UTF8Decode('gähn')));
end;
Ich habe bisher nur in einer Standard Windows-Umgebung getestet (um mit Turbo-Delphi vergleichen zu können). Linux mache ich noch...
-Michael

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: uppercase und lowercase

Beitrag von mse »

mschnell hat geschrieben:
mse hat geschrieben:Unter Windows ist dies leider eine Tatsache, vielleicht kannst du dich noch an mein Gezeter auf fpc-devel erinnern.
In Linux nicht ?!?!?!
Nein, siehe meinen Beitrag von 2008-10-16 12:49 in diesem Thema.
Verstehe ich nicht. Was hat die Kodierung der Quell-Dateien damit zu tun ? Sie Strings haben den richtigen Typ und vor dem Aufruf der passenden uppcase() den richtigen Inhalt. Nach uppercase() sind die ASCII-Zeichen konvertiert, die Umlaute nicht.
Was hat das mit utf8 zu tun? (Auf utf8-Strings will ich ja erstmal gar nicht eingehen.). Meine tests sind mit Widestrings (anscheinend ucs16 Kodierung, jedenfalls 16 bit pro character) und mit ANSI-Strings ("lokale"-abhängige ANSI-Kodierung, jedenfalls genau 8 bit pro Zeichen, keine utf-Erweiterung). Das sollten die entsprechenden Funktionen dich in jedem Fall korrekt verarbeiten können !!
Bitte poste mal deinen test code und gib an, in welcher Codierung der Quelltext gespeichert wurde, was die Systemcodierung deines Betriebssystems ist und ob FPC den Parameter -Fcutf8 oder einen anderen -Fc* parameter sieht.
Bitte liste auch die erhaltenen Testresultate.

Martin

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: uppercase und lowercase

Beitrag von mschnell »

OK, Monatg, wenn ich wieder im Büro bin...

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

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: uppercase und lowercase

Beitrag von mse »


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: uppercase und lowercase

Beitrag von mschnell »

Das ist ja wohl eher ein bug als ein feature....

-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: uppercase und lowercase

Beitrag von mschnell »

Hier ist der

Code: Alles auswählen

procedure TForm41.Button1Click(Sender: TObject);
var
  s1, s2, s3: string;
  c1: char;
  i1: Integer;
  su1, su2: UTF8String;
  sw1, sw2: Widestring;
  ss1, ss2: ShortString;
  sa1, sa2: AnsiString;
begin
  s1  := 'abcdefhäöü';
  s2  := UpperCase(s1);
  sa1 := 'abcdefhäöü';
  sa2 := AnsiUpperCase(sa1);
  c1  := s1[1];
  su1 := AnsiToUtf8(s1);
  su2 := su1; // UTF8LowerCase(su1);
  sw1 := s1;
  sw2 := WideUpperCase(sw1);
  s3  := sw2;
  ss1 := s1;
  ss2 := Uppercase(ss1);
  Memo1.Lines.Add(s1);
  Memo1.Lines.Add(s2);
  Memo1.Lines.Add(s3);
  Memo1.Lines.Add(su1);
  Memo1.Lines.Add(su2);
  Memo1.Lines.Add(sw1);
  Memo1.Lines.Add(sw2);
  Memo1.Lines.Add(ss1);
  Memo1.Lines.Add(ss2);
  Memo1.Lines.Add(sa1);
  Memo1.Lines.Add(sa2);
  i1 := sizeof(c1);
  Memo1.Lines.Add('-' + ' ' + inttostr(i1));
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: uppercase und lowercase

Beitrag von mse »

mschnell hat geschrieben:Hier ist der
Da fehlt doch noch was? ;-)
mse hat geschrieben: Bitte poste mal deinen test code und gib an, in welcher Codierung der Quelltext gespeichert wurde, was die Systemcodierung deines Betriebssystems ist und ob FPC den Parameter -Fcutf8 oder einen anderen -Fc* parameter sieht.
Bitte liste auch die erhaltenen Testresultate.

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: uppercase und lowercase

Beitrag von mschnell »

mse hat geschrieben:
mschnell hat geschrieben:Hier ist der
Da fehlt doch noch was? ;-)
Guck mal genau hin: da steht "hier ist der code" :) :) :) :)
mse hat geschrieben:gib an, in welcher Codierung der Quelltext gespeichert wurde,
Wie bekomme ich das heraus ? In Delphi (wo es funktioniert) habe ich ein Projekt angelegt den Code getippert und abgespeichert. In Lazarus (wo es nicht funktioniert) habe ich ein Projekt angelegt den Code getippert und abgespeichert. Das ist jedenfalls eine massive Inkompatibilität. Defaultmässig sollte sich Lazarus doch möglichst wie Delphi verhalten ?!?!?!?!?
mse hat geschrieben: was die Systemcodierung deines Betriebssystems ist
Wie bekomme ich das heraus ?
mse hat geschrieben: und ob FPC den Parameter -Fcutf8 oder einen anderen -Fc* parameter sieht.
Das steht vermutlich irgendwo in den Project Options ???? Das ist aber jedenfalls eine massive Inkompatibilität. Defaultmässig sollte sich Lazarus doch möglichst wie Delphi verhalten ?!?!?!?!?
mse hat geschrieben: Bitte liste auch die erhaltenen Testresultate.
Was ich herausbekomme poste ich morgen im Büro... Testresultate hatte ich doch klar beschrieben: Delphi: Großbuchstaben für ASCII-Zeichen und Umlaute, Lazarus Großbuchstaben für ASCII-Zeichen, Kleinbuchstaben für Umlaute.

-Michael

monta
Lazarusforum e. V.
Beiträge: 2809
Registriert: Sa 9. Sep 2006, 18:05
OS, Lazarus, FPC: Linux (L trunk FPC trunk)
CPU-Target: 64Bit
Wohnort: Dresden
Kontaktdaten:

Re: uppercase und lowercase

Beitrag von monta »

mschnell hat geschrieben:
mse hat geschrieben:gib an, in welcher Codierung der Quelltext gespeichert wurde,
Wie bekomme ich das heraus ?
Im Kontextmenü des Quellcodefensters unter Dateieinstellung >> Kodieren sollte das wohl sein.
Das steht vermutlich irgendwo in den Project Options ?
oder in der fpc.cfg würde ich mal sagen.
Johannes

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: uppercase und lowercase

Beitrag von mse »

mschnell hat geschrieben:Wie bekomme ich das heraus ?
Gut, dann treffe ich mal einige Annahmen:
- Du arbeitest mit einem deutschen Windows, dann ist die Systemcodierung cp1252.
http://en.wikipedia.org/wiki/Windows-1252
- Du hast Lazarus 0.9.26, FPC 2.2.2, hast fpc.cfg nicht verändert und benützt die default-Einstellungen.
In übrigen verlasse ich mich auf die Aussagen von Jonas Maebe:
http://www.mail-archive.com/fpc-pascal% ... 14177.html
In früheren FPC Versionen war das glaube ich anders gelöst.
-Der Quellcode ist in utf-8 gespeichert, es gibt keinen BOM.

Code: Alles auswählen

 
var
  s1, s2, s3: string; //in {$mode objfpc}{$h+} sind dies ansistrings
  c1: char;
  i1: Integer;
  su1, su2: UTF8String;
  sw1, sw2: Widestring;
  ss1, ss2: ShortString;
  sa1, sa2: AnsiString;
  wstr1,wstr2,wstr3,wstr4: widestring;
 
begin
  s1  := 'abcdefhäöü';
   //im quelltext steht hier  'abcdefh'#195#164#195#182#195#188
  s2  := UpperCase(s1); 
   //dies ist ASCII uppercase,
   //resultat:                'ABCDEFH'#195#164#195#182#195#188
  sa1 := 'abcdefhäöü';
   //im quelltext steht hier  'abcdefh'#195#164#195#182#195#188
  sa2 := AnsiUpperCase(sa1);
   //hier wird die Windows Funktion CharUpperBuf() aufgerufen,
   //sie erwartet cp1252 codierung und gibt cp1252 zurück.
   //sa1 in cp1252 interpretiert bedeutet
   //                         'abcdefhäöü'
   //resultat:                'ABCDEFHäöü'
  c1  := s1[1];
  su1 := AnsiToUtf8(s1);
(*
 
function AnsiToUtf8(const s : ansistring): UTF8String;{$ifdef SYSTEMINLINE}inline;{$endif}
  begin
    Result:=Utf8Encode(s);
  end;
 
function UTF8Encode(const s : WideString) : UTF8String;
  var
    i : SizeInt;
    hs : UTF8String;
  begin
    result:='';
    if s='' then
      exit;
    SetLength(hs,length(s)*3);
    i:=UnicodeToUtf8(pchar(hs),length(hs)+1,PWideChar(s),length(s));
    if i>0 then
      begin
        SetLength(hs,i-1);
        result:=hs;
      end;
  end;
  
procedure Win32Ansi2WideMove(source:pchar;var dest:widestring;len:SizeInt);
  var
    destlen: SizeInt;
  begin
    // retrieve length including trailing #0
    // not anymore, because this must also be usable for single characters
    destlen:=MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, source, len, nil, 0);
    // this will null-terminate
    setlength(dest, destlen);
    MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, source, len, @dest[1], destlen);
  end;
 
*)
    // 'abcdefhäöü' wird in von cp-1252 in Unicode gewandelt,
    // ergibt:
    // 'abcdefh'#195#164#195#182#195#188', in utf-8 codiert:
    // 'abcdefh'#195#131#194#164#195#131#194#182#195#131#194#188
 
  su2 := su1; // UTF8LowerCase(su1);
  sw1 := s1;
    // 'abcdefhäöü' wird in von cp-1252 in Unicode gewandelt,
    // ergibt:
    // 'abcdefh'#195#164#195#182#195#188' = 'abcdefhäöü'
 
  sw2 := WideUpperCase(sw1);
    // 'abcdefhäöü' -> 'ABCDEFHäöü' (Unicode)
  s3  := sw2;
    // Unicode 'ABCDEFHäöü' wird auf cp1252 gewandelt, ergibt:
    //  'ABCDEFH'#195#164#195#182#195#188 oder 'ABCDEFHäöü'
  ss1 := s1;
    //ss1 = 'abcdefh'#195#164#195#182#195#188
  ss2 := Uppercase(ss1);
    //ASCII uppercase = 'ABCDEFH'#195#164#195#182#195#188
  wstr1:= utf8decode(su1);
  wstr2:= utf8decode(su2);
  wstr3:= utf8decode(ansistring(sw1));
  wstr4:= utf8decode(ansistring(sw2));
{
 //Lazarus interpretiert die übergebenen ansistrings als utf-8
 
  Memo1.Lines.Add(s1); 
  //'abcdefh'#195#164#195#182#195#188 -> 'abcdefhäöü'  
  Memo1.Lines.Add(s2);
  //'ABCDEFH'#195#164#195#182#195#188 -> 'ABCDFHäöü'
  Memo1.Lines.Add(s3);
  //'ABCDEFH'#195#164#195#182#195#188 -> 'ABCDFHäöü'
  Memo1.Lines.Add(su1);
  //'abcdefh'#195#131#194#164#195#131#194#182#195#131#194#188 ->
  //'abcdefhäöü'
  Memo1.Lines.Add(su2);
  //'abcdefh'#195#131#194#164#195#131#194#182#195#131#194#188 ->
  //'abcdefhäöü'
  Memo1.Lines.Add(sw1);
  //sw1 wird von Unicode in cp1252 gewandelt und als utf8 interpretiert:
  //'abcdefh'#195#164#195#182#195#188 -> 'abcdefhäöü'
  Memo1.Lines.Add(sw2);
  //sw2 wird von Unicode in cp1252 gewandelt und als utf8 interpretiert:
  //'ABCDEFH'#195#164#195#182#195#188 -> 'ABCDEFHäöü'
  //Und so weiter...
  Memo1.Lines.Add(ss1);
  Memo1.Lines.Add(ss2);
  Memo1.Lines.Add(sa1);
  Memo1.Lines.Add(sa2);
  i1 := sizeof(c1);
  Memo1.Lines.Add('-' + ' ' + inttostr(i1));
}
end.
 
Martin

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: uppercase und lowercase

Beitrag von mschnell »

mse hat geschrieben:Gut, dann treffe ich mal einige Annahmen:
- Du arbeitest mit einem deutschen Windows, dann ist die Systemcodierung cp1252.
http://en.wikipedia.org/wiki/Windows-1252
Ich vermute dass Du da recht hast.
mse hat geschrieben:- Du hast Lazarus 0.9.26, FPC 2.2.2, hast fpc.cfg nicht verändert und benützt die default-Einstellungen.
In übrigen verlasse ich mich auf die Aussagen von Jonas Maebe:
http://www.mail-archive.com/fpc-pascal% ... 14177.html
In früheren FPC Versionen war das glaube ich anders gelöst.
In den Projekt optionen finde ich nichts was darauf hinweist, in fpc.cfg finde ich kein "Fc" irgendwas.
mse hat geschrieben:-Der Quellcode ist in utf-8 gespeichert, es gibt keinen BOM.
Tja, Im kontextmenue des Editors finde ich tatsächlich utf8.Wenn ich mir aber den Lazarus Quellcode der Unit mit einem Hex-Editor anschaue, sehe ich doppelbyte-Zeichen und am Anfang steht FF FE. Das sieht mir nach UCS2 und nicht nach utf8 aus. Merkwürdigerweise steht da für ä "00 E4" ist das korrekt ?

Der Quellcode der Delphi-unit ist einfaches ANSI - vermutlich mit der in Windows eingestellten Codepage.

-Michael
Zuletzt geändert von mschnell am Di 21. Okt 2008, 10:13, insgesamt 1-mal geändert.

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

Re: uppercase und lowercase

Beitrag von theo »

mschnell hat geschrieben: Tja, Im kontextmenue des Editors finde ich tatsächlich utf8.Wenn ich mir aber den Lazarus Quellcode der Unit mit einem Hex-Editor anschaue, sehe ich doppelbyte-Zeichen und am Anfang steht FF FE. Das sieht mir nach UCS2 und nicht nach utf8 aus. Merkwürdigerweise steht da für ä "00 E4" ist das korrekt ?

BOM UTF-16 Little Endian: $FF $FE
ä: dez:228 UCS-2:$00E4 UTF8:$C3 $A4

Antworten