UTF-8 Gleichheitsoperator Bug?
Re: UTF-8 Gleichheitsoperator Bug?
Ok, ich hab' nun wieder eine Version gemacht, die den Vergleich der beiden UTF-8-Strings, der "ungleich" ergibt durchführt (anbei) - quasi das Problem aus meinem Ursprungsposting:
mit Codetyphon 5.5/3.1.1:
Ausgabe:
wärme
wärme
6
6
5
5
65001
0
ungleich
Der eine UTF-8-String liefert in diesem Fall tatsächlich einen anderen Wert für StringCodePage, nämlich 65001 anstelle von 0....
Edit:
mit Codetyphon 5.7/3.1.1 ergibt sich nun:
Ausgabe:
wärme
wärme
6
6
5
5
65001
0
gleich
mit Codetyphon 5.5/3.1.1:
Ausgabe:
wärme
wärme
6
6
5
5
65001
0
ungleich
Der eine UTF-8-String liefert in diesem Fall tatsächlich einen anderen Wert für StringCodePage, nämlich 65001 anstelle von 0....
Edit:
mit Codetyphon 5.7/3.1.1 ergibt sich nun:
Ausgabe:
wärme
wärme
6
6
5
5
65001
0
gleich
- Dateianhänge
-
20160310b.zip
- (204.97 KiB) 60-mal heruntergeladen
Zuletzt geändert von HHick123 am Fr 11. Mär 2016, 14:02, insgesamt 8-mal geändert.
Re: UTF-8 Gleichheitsoperator Bug?
Wenn die CodePage gesetzt wird, brauchst du nichts mehr konvertieren, das macht fpc automatisch, weil die Code-Pages ja jetzt bekannt sind.
Michl, was ich jetzt nicht verstehe ist, ist warum AnsiToUtf8 unbedingt entfernt werden muss, ich war der festen Überzeugung, das wäre jetzt wirkungslos...
So geht's jedenfalls:
Ich persönlich finde aber die Version mit expliziter Umwandlung, ohne das SetCodePage, besser - da weiß man direkt, was passiert, und man kann durchgängig mit "string" arbeiten und muss nicht auf den "rawbytestring" ausweichen.
Michl, was ich jetzt nicht verstehe ist, ist warum AnsiToUtf8 unbedingt entfernt werden muss, ich war der festen Überzeugung, das wäre jetzt wirkungslos...
So geht's jedenfalls:
Code: Alles auswählen
procedure Initialize;
var
rs:rawbytestring;
sb,sc:string;
l:TListEnumerator;
begin
setlength(dictionary,0);
assignfile(f,'KKS.csv');
reset(f);
while not(eof(f)) do
begin
readln(f,rs);
SetCodePage(rs,1252,false);
// sb:=AnsiToUTF8(rs);
sb := rs;
l.Init(sb,';'); //Breakpoint 1
// sc:=AnsiToUTF8(l.NextItem);
sc := L.NextItem;
setlength(dictionary,length(dictionary)+1); //Breakpoint 2
dictionary[length(dictionary)-1].GermanLong:=sc;
end;
closefile(f);
end;
Code: Alles auswählen
procedure Initialize;
var
rs,sb,sc:string;
l:TListEnumerator;
begin
setlength(dictionary,0);
assignfile(f,'KKS.csv');
reset(f);
while not eof(f) do
begin
readln(f, rs);
sb := WinCPToUTF8(rs);
l.Init(sb, ';');
sc := l.Nextitem;
setlength(dictionary,length(dictionary)+1);
dictionary[length(dictionary)-1].GermanLong:=sc;
end;
closefile(f);
end;
Re: UTF-8 Gleichheitsoperator Bug?
Sorry, hab da einen Denkfehler gehabt, da ich nur das Endergebnis schnell getestet hatte. Die Stringmagic funktioniert nur mit vordefinierten Strings (siehe http://wiki.freepascal.org/FPC_Unicode_ ... _code_page, wobei der Begriff "Static" ungenau ist und durch "Vorbelegt" in der offiziellen Dokumentation ersetzt wurde, ist aber ein anderes Thema).
So wäre es richtig:
Eine Stringkonstante im Quelltext wird mit der Codepage CP_ACP initialisiert, siehe z.B.: http://wiki.freepascal.org/FPC_Unicode_ ... dentifiers.
Da du einen Ansistring einliest, Lazarus einen Hack macht und intern immer UTF8 kodierte Strings verwendet (siehe http://wiki.freepascal.org/Better_Unico ... in_Lazarus), ist es das Einfachste, gleich die Kodierung des zu verarbeitenden Strings zu UTF8 zu ändern und damit weiter zu arbeiten. Daher sind die Ausgaben richtig.
Wie CT mit Strings verfährt, weiß ich nicht. Scheinbar machen sie diesen Hack nicht und man muss sich selber um die entsprechende Kodierung kümmern.
So wäre es richtig:
Code: Alles auswählen
procedure Initialize;
var
rs: RawByteString;
sb, sc:string;
l:TListEnumerator;
begin
setlength(dictionary,0);
assignfile(f,'KKS.csv');
reset(f);
while not(eof(f)) do
begin
readln(f, rs);
SetCodePage(rs, 1252, False);
SetCodePage(rs, CP_UTF8, True); // Diese Zeile einfügen
sb := rs;
// sb:=AnsiToUTF8(rs);
l.Init(sb,';'); //Breakpoint 1
// sc:=AnsiToUTF8(l.NextItem);
sc:=l.NextItem;
setlength(dictionary,length(dictionary)+1); //Breakpoint 2
dictionary[length(dictionary)-1].GermanLong:=sc;
end;
closefile(f);
end;
Da du einen Ansistring einliest, Lazarus einen Hack macht und intern immer UTF8 kodierte Strings verwendet (siehe http://wiki.freepascal.org/Better_Unico ... in_Lazarus), ist es das Einfachste, gleich die Kodierung des zu verarbeitenden Strings zu UTF8 zu ändern und damit weiter zu arbeiten. Daher sind die Ausgaben richtig.
Wie CT mit Strings verfährt, weiß ich nicht. Scheinbar machen sie diesen Hack nicht und man muss sich selber um die entsprechende Kodierung kümmern.
Es wird UTF8Encode aufgerufen. Allerdings ist es tatsächlich wirkungslos, wenn eine schon UTF8 kodierter String übergeben wird, daher nicht notwendig (wenn man nicht, wie ich, vergisst die CodePage des Strings nach UTF8 zu ändern).wp_xyz hat geschrieben:Michl, was ich jetzt nicht verstehe ist, ist warum AnsiToUtf8 unbedingt entfernt werden muss, ich war der festen Überzeugung, das wäre jetzt wirkungslos...
Code: Alles auswählen
type
TLiveSelection = (lsMoney, lsChilds, lsTime);
TLive = Array[0..1] of TLiveSelection;
Re: UTF-8 Gleichheitsoperator Bug?
Vielleicht noch zur Ergänzung:
Dieser Test schlägt fehlt, da die Ausgangskodierung nicht bekannt ist:
Daher muss man diese definieren:
Nun kann man aber auch gleich die CodePage des Strings identisch ändern, ohne AnsiToUTF8 oder dgl:
So gänge es auch:
Dieser Test schlägt fehlt, da die Ausgangskodierung nicht bekannt ist:
Code: Alles auswählen
procedure TForm1.Button1Click(Sender: TObject);
const
StrCP1252 = #$80#$C4#$D6#$8C#$A5;
var
rs: RawByteString;
s: String;
begin
rs := StrCP1252;
s := AnsiToUtf8(rs);
Caption := IntToStr(StringCodePage(s)) + ' ' + s;
end;
Code: Alles auswählen
procedure TForm1.Button1Click(Sender: TObject);
const
StrCP1252 = #$80#$C4#$D6#$8C#$A5;
var
rs: RawByteString;
s: String;
begin
rs := StrCP1252;
SetCodePage(rs, 1252, False);
s := AnsiToUtf8(rs);
Caption := IntToStr(StringCodePage(s)) + ' ' + s;
end;
Code: Alles auswählen
procedure TForm1.Button1Click(Sender: TObject);
const
StrCP1252 = #$80#$C4#$D6#$8C#$A5;
var
rs: RawByteString;
s: String;
begin
rs := StrCP1252;
SetCodePage(rs, 1252, False);
SetCodePage(rs, CP_UTF8, True);
s := rs;
Caption := IntToStr(StringCodePage(s)) + ' ' + s;
end;
Code: Alles auswählen
procedure TForm1.Button1Click(Sender: TObject);
const
StrCP1252 = #$80#$C4#$D6#$8C#$A5;
var
s: String;
begin
s := StrCP1252;
SetCodePage(RawByteString(s), 1252, False);
SetCodePage(RawByteString(s), CP_UTF8, True);
Caption := IntToStr(StringCodePage(s)) + ' ' + s;
end;
Code: Alles auswählen
type
TLiveSelection = (lsMoney, lsChilds, lsTime);
TLive = Array[0..1] of TLiveSelection;
Re: UTF-8 Gleichheitsoperator Bug?
Und warum geht das nicht (ich bleibe bei dem von HHick123 geposteten Beispiel)? Hier wird rs als String für die Codepage 1252 deklariert, dann müsste bei "s := rs" doch die Umwandlung nach UTF8 richtig werden - was aber nicht so ist:
Code: Alles auswählen
procedure Initialize;
type
CP1252String = type Ansistring(1252); // <------
var
rs: CP1252String; // <-----
s: String;
l: TListEnumerator;
begin
SetLength(dictionary, 0);
assignFile(f, 'KKS.csv');
reset(f);
while not eof(f) do
begin
readln(f, rs);
s := rs;
l.Init(s, ';');
setlength(dictionary,length(dictionary)+1);
dictionary[length(dictionary)-1].GermanLong:=l.NextItem;
end;
closefile(f);
end;
Re: UTF-8 Gleichheitsoperator Bug?
Ich habe mich sehr ausgiebig mit den Strings befasst (an die hundert Tests habe ich noch rumliegen) und kenne noch einige unveröffentliche Bugs mit ACP-Strings unter Windows, muss aber auch immer wieder spezielle Verhalten in kleinen Tests gegentesten. Trotzdem versuche ich es mal:
Lazarus macht bei der Verwendung der LCL unter Windows einen Hack und definiert die Defaultsystemcodepage als UTF8. Eigentlich ist das falsch, da normalerweise eine länderspezifische Ansicodepage vom System verwendet wird (man will längerfristig auf Widestrings umswitchen, diese Lösung stellt daher nur ein Zwischenschritt für die nächsten ... Jahre dar).
Nicht desto trotz wird eine String-Variable mit 0 (CP_ACP, der Default-Ansicodepage) vorbelegt. Eine Zuweisung eines Strings zu einem anderen String ohne vordefinierter Codepage (CP_ACP) führt zur Kopie des Strings, nicht zur Umwandlung. Das kann man z.B. in dem zuvor geposteten Code so testen:Es wird der Referenzzähler des Strings hochgezählt.
Die Codemagic kann man nutzen, wenn man Strings mit vordefinierter Codepage verwendet:
MMn viel verwirrender ist, dass z.B. ein UTF8String auch jede andere Codepage bei entsprechender Zuweisung erhalten kann. Dazu hatte ich mal einen Bugreport http://bugs.freepascal.org/view.php?id=29651 gemacht. Daher wäre meine Empfehlung sämtliche mit Ansicodepagen vordefinierten Stringtypen, wie den UTF8String zu entfernen, da sie nicht halten, was sie versprechen.
Dass ein ReadLn(f, rs) direkt in eine CP1252 definierten String nicht funktioniert (in deinem Beispiel), liegt an der Definition der DefaultFileSystemCodepage (der vermeintliche eingelesene UTF8-String wird dabei per Stringmagic in einen CP1252 konvertiert und dies führt zu dem Fragezeichen).
Warum das Ganze? Das kann ich leider nicht beantworten. Die einzige Erklärung, die mir bei diversen Bugreports immer wieder genannt wurde, ist, dass Delphi sich genau so verhält. Eigentlich sind alle Besonderheiten mit den neuen Strings auf dieser Seite beschrieben: http://wiki.freepascal.org/FPC_Unicode_support. Leider versteht man die Sätze mit ihrer Tragweite zumeist erst, wenn man praktische Probleme hat.
Lazarus macht bei der Verwendung der LCL unter Windows einen Hack und definiert die Defaultsystemcodepage als UTF8. Eigentlich ist das falsch, da normalerweise eine länderspezifische Ansicodepage vom System verwendet wird (man will längerfristig auf Widestrings umswitchen, diese Lösung stellt daher nur ein Zwischenschritt für die nächsten ... Jahre dar).
Nicht desto trotz wird eine String-Variable mit 0 (CP_ACP, der Default-Ansicodepage) vorbelegt. Eine Zuweisung eines Strings zu einem anderen String ohne vordefinierter Codepage (CP_ACP) führt zur Kopie des Strings, nicht zur Umwandlung. Das kann man z.B. in dem zuvor geposteten Code so testen:
Code: Alles auswählen
WriteLn(StringRefCount(rs));
s := rs;
WriteLn(StringRefCount(rs));
Die Codemagic kann man nutzen, wenn man Strings mit vordefinierter Codepage verwendet:
Code: Alles auswählen
procedure Initialize;
type
CP1252String = type Ansistring(1252);
var
cs: CP1252String;
s: String;
su: UTF8String;
l: TListEnumerator;
begin
setlength(dictionary,0);
assignfile(f,'KKS.csv');
reset(f);
while not(eof(f)) do
begin
readln(f, s);
SetCodePage(RawByteString(s), 1252, False);
cs := s;
WriteLn(cs, StringRefCount(cs));
su := cs;
WriteLn(su, StringRefCount(cs));
l.Init(su,';');
setlength(dictionary,length(dictionary)+1);
dictionary[length(dictionary)-1].GermanLong:=l.NextItem;;
end;
closefile(f);
end;
Dass ein ReadLn(f, rs) direkt in eine CP1252 definierten String nicht funktioniert (in deinem Beispiel), liegt an der Definition der DefaultFileSystemCodepage (der vermeintliche eingelesene UTF8-String wird dabei per Stringmagic in einen CP1252 konvertiert und dies führt zu dem Fragezeichen).
Warum das Ganze? Das kann ich leider nicht beantworten. Die einzige Erklärung, die mir bei diversen Bugreports immer wieder genannt wurde, ist, dass Delphi sich genau so verhält. Eigentlich sind alle Besonderheiten mit den neuen Strings auf dieser Seite beschrieben: http://wiki.freepascal.org/FPC_Unicode_support. Leider versteht man die Sätze mit ihrer Tragweite zumeist erst, wenn man praktische Probleme hat.
Code: Alles auswählen
type
TLiveSelection = (lsMoney, lsChilds, lsTime);
TLive = Array[0..1] of TLiveSelection;
Re: UTF-8 Gleichheitsoperator Bug?
Danke, das ist alles sehr verwirrend... Ich lerne daraus: Beim Umgang mit Dateien fühle ich mich darin bestätigt, einfach mit "string" zu arbeiten und die entsprechenden Konvertierungsroutinen aufzurufen, anstatt auf die schlecht dokumentierten Tricks des Compilers zu vertrauen, zumal das durch die SetCodePage-Aufrufe auch nicht kürzer wird. Aus diesem Grund ist auch die Umstellung von fpc von v2.6.4 auf 3.0 an fpspreadsheet ohne nötige Änderungen vorübergegangen (und da gibt es in den alten Excel-Formaten eine Menge in Ansi).
Re: UTF-8 Gleichheitsoperator Bug?
Hallo,
noch ein Nachtrag von meiner Seite:
Nachdem ich nun doch etwas verzweifelt war mit CT (vorallem hatte ich noch ein zweites Problem, das ich nur kurz in einem meiner obigen Postings ansprach: Nämlich, dass ich die UTF-8-Codierung immer wieder "verlor", d.h. sie waren wieder ANSI und das passierte, wie sich zeigte z.B. unter bestimmten Umständen, wenn ich sie mit dem "+"-Operator zusammenfügte, und das ist ja nicht gerade eine seltene Sache...), hab' ich nun CT5.7 (welches vor ein paar Tager released wurde) probiert. Anscheinend wurde tatsächlich etwas gemacht (oder es lag vorher an meinen Einstellungen der 5.5er-Version). Das Verhalten dürfte nun bezüglich der Thematik dieses Threads, soweit ich das gesehen habe, Lazarus 1.6 entsprechen.
Entsprechende Edits hab' ich in meine Postings oben eingefügt.
Zumal im Lazarusforum
Denn im nachhinein denke ich, es war vorallem ein Problem von CT 5.5 (oder vielleicht auch nur meiner Compiler-Einstellungen der CT5.5-Installation?!)
Habe jedenfalls wieder einiges über strings gelernt...
Danke für die Unterstützung
LG Helmut
noch ein Nachtrag von meiner Seite:
Nachdem ich nun doch etwas verzweifelt war mit CT (vorallem hatte ich noch ein zweites Problem, das ich nur kurz in einem meiner obigen Postings ansprach: Nämlich, dass ich die UTF-8-Codierung immer wieder "verlor", d.h. sie waren wieder ANSI und das passierte, wie sich zeigte z.B. unter bestimmten Umständen, wenn ich sie mit dem "+"-Operator zusammenfügte, und das ist ja nicht gerade eine seltene Sache...), hab' ich nun CT5.7 (welches vor ein paar Tager released wurde) probiert. Anscheinend wurde tatsächlich etwas gemacht (oder es lag vorher an meinen Einstellungen der 5.5er-Version). Das Verhalten dürfte nun bezüglich der Thematik dieses Threads, soweit ich das gesehen habe, Lazarus 1.6 entsprechen.

Entsprechende Edits hab' ich in meine Postings oben eingefügt.
Michl hat geschrieben:Gesteinigt wirst du nicht, musst nur zehn Liegestütze zur Strafe machen![]()
Ja, ok, ich mach nun freiwillig 20 Liegestütz. Mit Lazarus wär' ich vermutlich schneller am Ziel gewesen.mschnell hat geschrieben: Das ist kein Bug von Lazarus.
Zumal im Lazarusforum

Denn im nachhinein denke ich, es war vorallem ein Problem von CT 5.5 (oder vielleicht auch nur meiner Compiler-Einstellungen der CT5.5-Installation?!)
Habe jedenfalls wieder einiges über strings gelernt...
Danke für die Unterstützung
LG Helmut