Lazarus 1.6RC2, FPC 3.0.0, LazUtils, LazUTF8, Writeln

Rund um die LCL und andere Komponenten
Antworten
Zeff
Beiträge: 7
Registriert: Fr 12. Feb 2016, 21:44
OS, Lazarus, FPC: Winux (Lazarus 2.2.6, FPC 3.2.2)
CPU-Target: 64Bit
Wohnort: Rheinbach

Lazarus 1.6RC2, FPC 3.0.0, LazUtils, LazUTF8, Writeln

Beitrag von Zeff »

Liebe Gemeinde,

dies ist mein erster Beitrag in diesem Forum. Bitte prügelt mich nicht gleich, wenn was falsch ist.

Die im Betreff genannte Version des Lazarus und FPC ist hier als 32Bit-Version auf einem Rechner mit Win7 64Bit installiert.
Nun zu meinem Problem, von dem ich nicht weiß, ob es sich um eines zwischen meinen Ohren oder einem in LazUTF8 handelt.
Projekt in Lazarus ist ein einfaches FP-Kommando-Zeilenprogramm. Im Projektinspektor wurden die LazUtils unter
"Benötigte Packages" hinzugefügt.

Writeln('äöü'); bewirkt, dass auf der Konsole (Eingabeaufforderung) 6 wirre Zeichen geschrieben werden, also hier keine
Umwandlung von UTF-8 nach Codepage 850 stattfindet.

Lautet der Code jedoch wie folgt:

Code: Alles auswählen

 Uses LazUTF8;
 Var Hstr : String;
  Begin
    Hstr := 'äöü';
    Writeln(Hstr);
  End.
erfolgt die Ausgabe der Zeichenkette auf der Konsole konvertiert.
Eine Umleitung der Ausgabe in eine Textdatei mit anschließender Betrachtung eines Hex-Editors bestätigt dies.
Beispielsweise hat der Char 'ä' in der Textdatei den Ordinalwert 132 ($84).

Worin liegt nun das Problem?

Danke im Voraus für eure Antworten.

Gruß, Andy
Zuletzt geändert von Lori am Sa 13. Feb 2016, 09:11, insgesamt 1-mal geändert.
Grund: Highlighter

Komoluna
Beiträge: 565
Registriert: So 26. Aug 2012, 09:03
OS, Lazarus, FPC: Windows(10), Linux(Arch)
CPU-Target: 64Bit

Re: Lazarus 1.6RC2, FPC 3.0.0, LazUtils, LazUTF8, Writeln

Beitrag von Komoluna »

Hallo Zeff,

Erstmal herzlich willkommen hier. Zu deiner Frage kann ich leider nichts sagen, aber hier ein paar Tipps fürs Posten von Beiträgen ;-)
  • Wenn du Code posten möchtest, benutze die Highlighter Funktion(über dem Eingabefeld) um den Code besser lesbar zu machen:

    Code: Alles auswählen

    procedure Test: Integer;
    begin
      Result:=5;
    end;
  • Als Titel solltest du eine möglichst knappe Beschreibung deines Problems nehmen, z.B. "Seltsames Verhalten der Konsole beim Ausgeben von Umlauten"
  • Wie du scheinbar bereits gefunden hast, kann man in seinem Profil angeben, welche OS, Lazarus und FPC version man benutzt, was eine erneute Angabe im Post meist unnötig macht(sieht man unter dem Post)
MFG

Komoluna
Programmer: A device to convert coffee into software.

Rekursion: siehe Rekursion.

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Lazarus 1.6RC2, FPC 3.0.0, LazUtils, LazUTF8, Writeln

Beitrag von Socke »

Zeff hat geschrieben:Worin liegt nun das Problem?
  • Ich nehme an, dein Quelltext ist in UTF-8 kodiert (Standardeinstellung).
  • Ich gehe auch davon aus, dass der Parameter -FcUTF-8 nicht an den Compiler übergeben wird (Standardeinstellung).
Daraus folgt jetzt:
  • Der Compiler nimmt an, dass dein Quelltext in der Systemcodepage (vermutlich CP 1252, Windows) kodiert ist.
  • Die Variable Hstr hat den Typ String; dem Typ String ist die CodePage CP_ACP (Systemcodepage) zugewiesen.
  • Daher wird die Stringkonstante 'äöü' einfach in das Programm kopiert (Codepage des Variablentyps = Systemcodepage); es findet keine Konvertierung statt.
  • Bei der Ausgabe findet ebenfalls keine Konvertierung statt, da die Systemcodepage bereits vorliegt.
Du hast verschiedene Möglichkeiten:

Code: Alles auswählen

program Project1;
Var Hstr : RawByteString;
Begin
Hstr := 'äöü';
SetCodePage(hstr, CP_UTF8, False);
Writeln(Hstr);
End.
Hier wird dem String der Typ RawByteString zugewiesen (keine Konvertierung durch den Compiler). Dem String wird die Codepage UTF-8 zugewiesen. Bei der Ausgabe wird der String in die Systemcodepage konvertiert.

Code: Alles auswählen

program Project1;
{$codepage utf-8}
Var Hstr : String;
Begin
Hstr := 'äöü';
Writeln(Hstr);
End.
Hier wird dem Compiler mitgeteilt, dass der Quelltext in UTF-8 vorliegt. Die Stringkonstante 'äöü' wird nicht konvertiert, da HStr die Codepage CP_ACP hat, die Stringkonstante die Codepage CP_UTF8 und der Quelltext ebenfalls CP_UTF8 hat. Bei der Ausgabe wird der Text in die Systemcodepage konvertiert.

Code: Alles auswählen

program Project1;
Var Hstr : RawByteString;
Begin
Hstr := 'äöü';
SetCodePage(hstr, CP_UTF8, False);
SetCodePage(Hstr, CP_ACP, True);
Writeln(Hstr);
End.
Hier geht der Compiler von der Quelltextcodepage 1252 aus; diese wird durch den ersten Aufruf von SetCodePage() korrigiert. Der zweite Aufruf konvertiert den String in die Systemcodepage. Bei der Ausgabe findet keine Konvertierung mehr statt.

Code: Alles auswählen

program Project1;
{$codepage utf-8}
Var Hstr : UTF8String;
  astring: ansistring;
Begin
Hstr := 'äöü';
astring := hstr;
Writeln(astring);
End.
Hier ist Vorsicht geboten. Der Compiler kennt die Codepage des Quelltextes (UTF-8) und führt keine Konvertierung durch (Hstr ist ebenfalls UTF-8). Bei der Zuweisung an astring (CP_ACP = Systemcodepage) findet keine Konvertierung statt, da die Hstr die Codepage des Quelltextes hat. Die Konvertierung zur Systemcodepage findet erst bei der Ausgabe statt.

Die Dokumentation findest du übrigens hier: http://wiki.freepascal.org/FPC_Unicode_ ... Ansistring
Vielleicht hilft es bei der Lektüre, wenn man "static code page" mit "Code page der Variablen (Datentyp)" und "dynamic code page" mit "Code page der konkreten Daten zur Laufzeit" übersetzt.

Edit: eine Variante ist mir noch eingefallen:

Code: Alles auswählen

program Project1;
{$codepage utf-8}
type
  string1252 = type string(1252);
 
Var Hstr : UTF8String;
  astring: string1252;
Begin
Hstr := 'äöü';
astring := hstr;
Writeln(astring);
End.
Hier wird ein Stringtyp mit bestimmter Codepage (1252) definiert. Da der Typ von Hstr die Codepage UTF-8 hat, wird bei der Zuweisung an astring (Codepage 1252) die Konvertierung durchgeführt.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Zeff
Beiträge: 7
Registriert: Fr 12. Feb 2016, 21:44
OS, Lazarus, FPC: Winux (Lazarus 2.2.6, FPC 3.2.2)
CPU-Target: 64Bit
Wohnort: Rheinbach

Re: Lazarus 1.6RC2, FPC 3.0.0, LazUtils, LazUTF8, Writeln

Beitrag von Zeff »

Vielen Dank erstmal für die Antworten!

@Komoluna: Danke für deine Hinweise. Ich bemühe mich für die Zukunft deine Vorschläge zu beherzigen.
@Lori: Danke für das nachträgliche highlighting meines Codes.

Ich glaube, mein beschriebenes Problem wurde nicht richtig verstanden. Bevor ich weiterschreibe, muss ich darauf hinweisen,
dass mit FPC 3.0 und in Lazarus 1.6 eine verbesserte Unicodeunterstützung (UTF-8) implementiert wurde. Im englischsprachigen
Wiki von FreePascal wird darauf hingewiesen: http://wiki.freepascal.org/Better_Unico ... in_Lazarus

Dies bedeutet, dass jetzt für Strings bzw. Ansistrings intern die Default-Codepage UTF-8 lautet. Alles, was von außen mit einer anderen
Codepage reinkommt und einem String zuwiesen wird, z. B. über ParamStr(x) von einer Konsole, wird nach UTF-8 konvertiert. Und
genauso ist es auch rückwärts mit Writeln.

Die UTF-8 Implementierung ist soweit gut gelungen, jedoch bei einer Konsolenausgabe mit Writeln, die einen String als Konstante
mit Umlaute enthält

Code: Alles auswählen

Writeln('äöü');
klappt das nicht. Umlaute sind auf der Konsole nicht lesbar.

Aber im Prinzip ist das kein Weltproblem. Wenn man konstante Strings zuerst einem deklarierten String zuordnet

Code: Alles auswählen

Hstr := 'äöü';
Writeln(Hstr);
und diesen mit Writeln ausgibt, ist die Welt wieder in Ordnung.

Gruß, Andy

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: Lazarus 1.6RC2, FPC 3.0.0, LazUtils, LazUTF8, Writeln

Beitrag von Michl »

Dazu hatte ich mal einen Abschnitt formuliert: http://wiki.freepascal.org/Lazarus_with ... Windows.29

Anbei die setdefaultcodepages.pas, einfach in die uses aufnehmen und schon sollte es passen.
Dateianhänge
setdefaultcodepages.pas
(1.21 KiB) 70-mal heruntergeladen

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

Zeff
Beiträge: 7
Registriert: Fr 12. Feb 2016, 21:44
OS, Lazarus, FPC: Winux (Lazarus 2.2.6, FPC 3.2.2)
CPU-Target: 64Bit
Wohnort: Rheinbach

Re: Lazarus 1.6RC2, FPC 3.0.0, LazUtils, LazUTF8, Writeln

Beitrag von Zeff »

Halo Michl,

du beschreibst in deinem verlinkten Beitrag genau das Problem, mit welchem ich hier das Thema eröffnete.
Du schlägst als Lösung die Abschaltung der UTF8-Unterstützung vor, wofür du sicherlich gute Gründe hast.

Ich selbst will das aber nicht. Soweit es möglich ist, schreibe ich alles, was zeichenbasiert ist, in UTF8. Klar, das erfordert
einiges Umdenken. Stringmanipulierende Routinen wie Delete, Copy, Insert usw. können nicht mehr angewendet werden,
weil diese byteorientiert arbeiten. Aber dafür stellt ja Lazarus Ersatzroutinen bereit: UTF8Delete, UTF8Copy, UTF8Insert, usw.

Danke für deine Unit "setdefaultcodepages". Diese funktioniert auch. Was mir jedoch mißfällt, dass in der Konsole die
Schriftart auf Lucida umgestellt wird.

Wie auch immer. Ich denke, dass Thema kann man hier langsam beenden. Der Sonderfall, dass Writeln('äöü') nicht richtig
funktioniert, lässt sich einfach umgehen, indem man 'äöü' erst einer Stringvariable zuweist und diese dann mit Writeln(Variable)
ausgibt. Mit dieser Lösung kann ich erstmal leben.

Gruß, Andy

Mathias
Beiträge: 6918
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Lazarus 1.6RC2, FPC 3.0.0, LazUtils, LazUTF8, Writeln

Beitrag von Mathias »

Ich habe es bis jetzt immer so gemacht, ohne irgendwelche Code-Pages-Einstellungen.

Code: Alles auswählen

WriteLn(UTF8ToConsole('äöü')); 
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: Lazarus 1.6RC2, FPC 3.0.0, LazUtils, LazUTF8, Writeln

Beitrag von Michl »

Zeff hat geschrieben:Du schlägst als Lösung die Abschaltung der UTF8-Unterstützung vor, wofür du sicherlich gute Gründe hast.
Nein, das hast du falsch verstanden. Ich habe nur Teile auf der Wikiseite hinzugefügt, als ich mich mit den ACP-Strings intensiver befasst hatte. Es ging mir nur um den verlinkten Abschnitt (die Codepage der Konsole auf die Systemcodepage zu stellen - in deinem Fall zu UTF8).
Zeff hat geschrieben:Danke für deine Unit "setdefaultcodepages". Diese funktioniert auch. Was mir jedoch mißfällt, dass in der Konsole die
Schriftart auf Lucida umgestellt wird.
Leider gibt es nicht viele Schriftarten, die UTF8-fähig sind lt. https://msdn.microsoft.com/de-de/librar ... 10%29.aspx:

Code: Alles auswählen

Die Konsole muss eine TrueType-Schriftart, z. B. Lucida Console oder Consolas, verwenden, um Zeichen anzuzeigen.
Bei einem kleinen Test habe ich eben festgestellt, dass bei Lucida Console viele UTF8-Chars nicht definiert sind und habe das Bsp. im Wiki nun auf Consolas geändert, da scheinen mehr Schriftzeichen hinterlegt zu sein.

Mathias hat geschrieben:Ich habe es bis jetzt immer so gemacht, ohne irgendwelche Code-Pages-Einstellungen.

Code: Alles auswählen

WriteLn(UTF8ToConsole('äöü')); 
Das funktioniert nur, wenn die Schriftzeichen auf der Console-Codepage vorhanden sind:

Code: Alles auswählen

  WriteLn('äöü-ḂӥԱẄɐ'); 
Der Test schlägt mit UTF8ToConsole bei mir fehl, mit Umstellung der Consolecodepage wird der String entsprechend angezeigt.

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

Mathias
Beiträge: 6918
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Lazarus 1.6RC2, FPC 3.0.0, LazUtils, LazUTF8, Writeln

Beitrag von Mathias »

WriteLn('äöü-ḂӥԱẄɐ');
Der Test schlägt mit UTF8ToConsole bei mir fehl, mit Umstellung der Consolecodepage wird der String entsprechend angezeigt.
Solche exotischen Zeichen habe ich bis jetzt nie gebraucht, ich war mit den deutschen Umlauten zu frieden.


Ich habe es mit Linux probiert, dort geht es sogar ohne UTF8ToConsole.

Dann wollte ich das Test-Project unter WinXP in der VB öffnen, dort werden die Zeichen nicht mal im Editor richtig dargestellt, dort werden nur Quadrate geschrieben, ausser dem Ẅ.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: Lazarus 1.6RC2, FPC 3.0.0, LazUtils, LazUTF8, Writeln

Beitrag von Michl »

Mathias hat geschrieben:Ich habe es mit Linux probiert, dort geht es sogar ohne UTF8ToConsole.
Ja. Linux nutzt als Standard UTF8.

Es gab Überlegungen, bei der Verwendung der LCL die KonsoleCodepage entsprechend der SystemCodepage einzustellen. Einen Patch hatte ich dazumal erstellt, aber nie hochgeladen, da man man dann ein abweichendes Verhalten bei reinen FPC-Programmen zu Lazarus-Programmen und immer diese andere Optik hätte.
Mathias hat geschrieben:Dann wollte ich das Test-Project unter WinXP in der VB öffnen, dort werden die Zeichen nicht mal im Editor richtig dargestellt, dort werden nur Quadrate geschrieben, ausser dem Ẅ.
Hast du mal den Font Consolas probiert? Wie zuvor geschrieben, scheint dieser mehr Zeichen definiert zu haben.

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

Mathias
Beiträge: 6918
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Lazarus 1.6RC2, FPC 3.0.0, LazUtils, LazUTF8, Writeln

Beitrag von Mathias »

Hast du mal den Font Consolas probiert? Wie zuvor geschrieben, scheint dieser mehr Zeichen definiert zu haben.
Unter XP gibt es die leider noch nicht.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Antworten