UTF8 Klassen

Zur Vorstellung von Komponenten und Units für Lazarus
Antworten
Benutzeravatar
AlterPascaler
Beiträge: 44
Registriert: Mo 26. Jun 2023, 18:56
OS, Lazarus, FPC: Linux, Lazarus, Free Pascal
CPU-Target: xxBit
Wohnort: Deutschland, NRW

UTF8 Klassen

Beitrag von AlterPascaler »

Moin,

angeregt von Jorg3000 Thread viewtopic.php?f=29&t=15258 möchte ich euch meine UTF8 Klasse vorstellen.

Ich hatte die Aufgabe nach solchen Chars 'üäößẶặǺǻǼǽǞǟǍǎḂḃÞþÇçĆćĊċ...' und Combining Chars zu parsen. Also Zeichen, die sich aus zwei Zeichen zusammensetzen. Siehe https://en.wikipedia.org/wiki/Combining_character

Mit der LazUTF8 unit geht das, sieht aber sehr kryptisch aus. Wenn man nach 3 Wochen seinen Code wieder anschaut, versteht man nur sehr schwer, was man da gemacht hat. Aus diesem Grunde habe ich mir eine Klasse geschrieben, die den Code besser verständlich macht.

Hier ein Beispiel:

Code: Alles auswählen

proceudre Demo01: Boolean;
var
  u: IbUtf8;
  i: Integer;
begin
  u:= TIbUtf8.Create('Thömäß');
  for i:= 1 to u.NumberOfChars do begin
    case u.Chars[i] of
      'ö': u.Chars[i]:= 'o';
      'ä': u.Chars[i]:= 'a';
      'ß': u.Chars[i]:= 's';
    end; 
  end;
  if u.Text = 'Thomas' then begin
    WriteLn('That''s right!');
  end;
end;
Achtet bitte auf "IbUtf8". Das 'I' steht für InterfacedObject, Das bedeutet für euch, dass die Klasse benutzt werden kann wie ein String, um das Aufräumen (Free) braucht ihr euch nicht zu kümmern.

Klar sollte sein, dass Komfort seinen Preis hat, ich will damit sagen, dass es deutlich langsamer ist, als über ein Array zu iterieren. Aber das gleiche Problem hat die "LazUTF8" auch. Das ist eben der Preis von UTF8.

Die Klasse und Doku findet ihr hier:https://gitlab.com/FpTuxe/tbutf8

Viele Grüße vom AltenPascaler

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

Re: UTF8 Klassen

Beitrag von theo »

Hallo AlterPascaler
Sieht gut aus, aber hat es einen Vorteil gegenüber dem Unistring, den ich vor über 10 Jahren mal gebastelt habe?
Dein gezeigtes Beispiel geht damit ja auch.
Gibt es andere Beispiele, die mehr zeigen?

Code: Alles auswählen

var
  s: TUniString;
  i: integer;
begin
  s := 'Thömäß';
  for i := 1 to s.length do
    case s[i] of
      'ö': s[i] := 'o';
      'ä': s[i] := 'a';
      'ß': s[i] := 's';
    end;
  if s = 'Thomas' then
     WriteLn('That''s right!');
end;  

Benutzeravatar
AlterPascaler
Beiträge: 44
Registriert: Mo 26. Jun 2023, 18:56
OS, Lazarus, FPC: Linux, Lazarus, Free Pascal
CPU-Target: xxBit
Wohnort: Deutschland, NRW

Re: UTF8 Klassen

Beitrag von AlterPascaler »

@Theo

Erstmal "unistring" kannte ich nicht, hätte mir wahrscheinlich viele Arbeit abgenommen. Es ist ein großes Problem in der Softwareentwicklung, das man die Sachen die andere schon programmiert haben nicht findet, so werden unzählige male die gleichen Aufgaben neu Entwickelt. So auch dieses Mal!

Dein Ansatz das über ein Record zumachen gefällt mit sehr gut. Damit hast du das Problem mit dem Aufräumen auch sehr schön gelöst. Auch die Sache mit den operatoren finde ich sehr gut. Sollte ich auch mal drüber nachdenken.

Ich denke das dein Ansatz 99% gleiche Ergebnisse liefert wie mein Ansatz. Bei mir war nach die Zielsetzung Combining Chars, was echt kein Spaß macht.

Hier die Unterschiede:
Testcode Auszug

Code: Alles auswählen

procedure TForm1.BTestClick(Sender: TObject);
var
  t: String;
begin
  t:= 'Thömäs' + #$E1#$B8#$B3#$CC#$84;
  Info('Der Test String, %s', [t]);

  UniStringTest(t);
  Info('');
  TbUtf8Test(t);
end;

procedure TForm1.UniStringTest(const aText: String);
var
  us: TUniString;
  p: Integer;
begin
  us:= aText;
  Info('UniString');
  for p:= 1 to us.Length do begin
    Info('Char %d, %s', [p, us.UTF8Chars[p]])
  end;
end;

procedure TForm1.TbUtf8Test(const aText: String);
var
  tb: IbUtf8;
  p: Integer;
begin
  tb:= TIbUtf8.Create(aText);
  Info('TbUtf8');
  for p:= 1 to tb.NumberOfChars do begin
    Info('Char %d, %s', [p, tb.Chars[p]])
  end;
end;

procedure TForm1.Info(const aText: String);
begin
  Memo1.Append(aText);
end;

procedure TForm1.Info(const FormatText: String; const Args: array of const);
begin
  Memo1.Append(Format(FormatText, Args));
end;
Ausgabe:
Der Test String, Thömäsḳ̄
UniString
Char 1, T
Char 2, h
Char 3, ö
Char 4, m
Char 5, ä
Char 6, s
Char 7, ḳ
Char 8, ̄

TbUtf8
Char 1, T
Char 2, h
Char 3, ö
Char 4, m
Char 5, ä
Char 6, s
Char 7, ḳ̄

Gruß
AP

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

Re: UTF8 Klassen

Beitrag von theo »

Zur "Normalisierung" hatte ich auch mal was gemacht:
viewtopic.php?t=2470

Damit kann man den String in eine einheitliche Form bringen.
z.B.

Code: Alles auswählen

uses character...
...
Memo1.Text:= TCharacter.Normalize_NFKC(Memo1.text);
Ist schon eine Weile her, vielleicht macht die LCL das mittlerweile auch.

Du kannst ja mal ausprobieren, ob es hilft. :wink:

Benutzeravatar
AlterPascaler
Beiträge: 44
Registriert: Mo 26. Jun 2023, 18:56
OS, Lazarus, FPC: Linux, Lazarus, Free Pascal
CPU-Target: xxBit
Wohnort: Deutschland, NRW

Re: UTF8 Klassen

Beitrag von AlterPascaler »

Danke Theo, schaue ich mir an.

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

Re: UTF8 Klassen

Beitrag von theo »

AlterPascaler hat geschrieben:
Fr 29. Dez 2023, 18:17
Danke Theo, schaue ich mir an.
Habe es eben ausprobiert.
"TCharacter.Normalize_NFKC" löst dein Problem leider nicht.

Benutzeravatar
AlterPascaler
Beiträge: 44
Registriert: Mo 26. Jun 2023, 18:56
OS, Lazarus, FPC: Linux, Lazarus, Free Pascal
CPU-Target: xxBit
Wohnort: Deutschland, NRW

Re: UTF8 Klassen

Beitrag von AlterPascaler »

Danke, ich schau es mir trotzdem an.

Antworten