UTF-16-Funktionen zur Zeichenkettenverarbeitung

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Socke
Lazarusforum e. V.
Beiträge: 3158
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:

UTF-16-Funktionen zur Zeichenkettenverarbeitung

Beitrag von Socke »

Hallo zusammen,

ich arbeite zurzeit mit einer externen Bibliothek, die ausschließlich UTF-16 für Strings verwendet; daher würde ich gerne die Datenverarbeitung in Pascal möglichst ebenfalls in UnicodeString halten.
Mir kommt es dabei seltsam vor, dass ich in Free Pascal diverse Funktionen nur für "AnsiString" (ggf. mit CodePage-Unterstützung) finde, aber für UnicodeString nicht einmal ein simples IntToStr vorhanden ist.
Ist es tatsächlich richtig für alle Konvertierungen von Integer nach UnicodeString eine implizite CodePage-Conversion zu nutzen? Oder bin ich einfach nur blind oder habe einen zu alten FPC?

Edit: ich sehe gerade in fpcsrc/rtl/inc/ustrings.inc, dass auch die Compiler-Funktionen wie fpc_Val_int64_unicodeStr auch nur eine CodePage-Konvertierung durchführen. Aber vielleicht weiß einer von euch noch mehr...
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

sstvmaster
Beiträge: 575
Registriert: Sa 22. Okt 2016, 23:12
OS, Lazarus, FPC: W10, L 2.2.6
CPU-Target: 32+64bit
Wohnort: Dresden

Re: UTF-16-Funktionen zur Zeichenkettenverarbeitung

Beitrag von sstvmaster »

LG Maik

Windows 10,
- Lazarus 2.2.6 (stable) + fpc 3.2.2 (stable)
- Lazarus 2.2.7 (fixes) + fpc 3.3.1 (main/trunk)

Socke
Lazarusforum e. V.
Beiträge: 3158
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: UTF-16-Funktionen zur Zeichenkettenverarbeitung

Beitrag von Socke »

sstvmaster hat geschrieben:
Sa 6. Mär 2021, 23:52
Hast du das schon gelesen?
Der erste Link bezieht sich auf die korrekte Verarbeitung von CodePoints. Diese sind in UTF-16 immer 2 Byte groß und insofern eher für UTF-8 relevant.
Den zweiten Link kenne ich schon. Eingangs wird dort tatsächlich meine Frage aufgeworfen, dann aber nicht weiter diskutiert:
Warum erhalte ich bei folgendem Code die Warnung "Warning: Implicit string type conversion from "AnsiString" to "UnicodeString""?

Code: Alles auswählen

var
  s: UnicodeString;
begin
  s := IntToStr(5);
end.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

PascalDragon
Beiträge: 825
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: UTF-16-Funktionen zur Zeichenkettenverarbeitung

Beitrag von PascalDragon »

Socke hat geschrieben:
Sa 6. Mär 2021, 23:39
ich arbeite zurzeit mit einer externen Bibliothek, die ausschließlich UTF-16 für Strings verwendet; daher würde ich gerne die Datenverarbeitung in Pascal möglichst ebenfalls in UnicodeString halten.
Mir kommt es dabei seltsam vor, dass ich in Free Pascal diverse Funktionen nur für "AnsiString" (ggf. mit CodePage-Unterstützung) finde, aber für UnicodeString nicht einmal ein simples IntToStr vorhanden ist.
Ist es tatsächlich richtig für alle Konvertierungen von Integer nach UnicodeString eine implizite CodePage-Conversion zu nutzen? Oder bin ich einfach nur blind oder habe einen zu alten FPC?[/url]
Gerne auch explizite Umwandlung, um die Warnung zu vermeiden, aber ja für sowas wie IntToStr gibt es keinen großartigen Grund da ein IntToUStr hinzuzufügen, da die Zeichen, die von der Funktion zurückgegeben werden alle eh sogar nur ASCII sind.

Für vieles anderes (zum Beispiel Unit StrUtils oder Classes.TStrings) existieren nur AnsiString Implementierungen.

Am sinnvollsten ist es aktuell für die Verarbeitung die Strings in UTF-8 umzuwandeln (Typ UTF8String) oder wenn du die LCL verwendest ist das eh die Standardcodepage.
FPC Compiler Entwickler

PascalDragon
Beiträge: 825
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: UTF-16-Funktionen zur Zeichenkettenverarbeitung

Beitrag von PascalDragon »

Socke hat geschrieben:
So 7. Mär 2021, 11:34
Warum erhalte ich bei folgendem Code die Warnung "Warning: Implicit string type conversion from "AnsiString" to "UnicodeString""?

Code: Alles auswählen

var
  s: UnicodeString;
begin
  s := IntToStr(5);
end.
Weil eventuell der AnsiString eine Codepage hat für die kein Konverter registriert ist. Da die Codepage erst zur Laufzeit wirklich feststeht kann dies der Compiler nicht beurteilen. Hierzu dann einfach eine explizite Umwandlung per UnicodeString(IntToStr(5)) durchführen. Oder UTF8String nutzen.
FPC Compiler Entwickler

Socke
Lazarusforum e. V.
Beiträge: 3158
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: UTF-16-Funktionen zur Zeichenkettenverarbeitung

Beitrag von Socke »

PascalDragon hat geschrieben:
So 7. Mär 2021, 15:04
Gerne auch explizite Umwandlung, um die Warnung zu vermeiden, aber ja für sowas wie IntToStr gibt es keinen großartigen Grund da ein IntToUStr hinzuzufügen, da die Zeichen, die von der Funktion zurückgegeben werden alle eh sogar nur ASCII sind.
Meine Idee war: bei der Konvertierung von ASCII nach UTF-16 muss ein weiteres Mal über den String iteriert werden - ein Schleifendurchlauf wird ohnehin für die Konvertierung der Zahl benötigt. Warum sollte man diese zweite Iteration überhaupt durchführen?

In der Praxis zeigt sich, dass es verdammt aufwändig ist, die Standardfunktion str() in Verbindung mit der impliziten CodePage-Konvertierung hinsichtlich der Geschwindigkeit zu schlagen.
Ich habe es nicht geschafft :(

Code: Alles auswählen

program Project1;
{$mode objfpc}
uses
  SysUtils, EpikTimer, math;

function IntToStrU(Value: LongWord): UnicodeString; inline;
const
  MAX_LONGWORD_DIGITS = 10;
var
  Digits: array[0..MAX_LONGWORD_DIGITS-1] of UnicodeChar;
  remainder: LongWord = 0;
  i: Integer;
begin
  Result := '';
  for i := high(Digits) downto Low(Digits) do
  begin
    DivMod(Value, 10, Value, remainder);
    Digits[i] := UnicodeChar(ord('0') + remainder);
    if Value = 0 then
      exit(Digits[i..MAX_LONGWORD_DIGITS-1]);
  end;
  exit(Digits);
end;

procedure Test_CP_Conversion(const data: array of LongInt);
var
  r: Array of UnicodeString;
  i: Integer;
begin
  SetLength(r{%H-}, Length(data));
  for i := low(data) to high(data) do
    r[i] := IntToStr(data[i]);
end;

procedure Test_UTF16_Native(const data: array of LongInt);
var
  r: Array of UnicodeString;
  i: Integer;
begin
  SetLength(r{%H-}, Length(data));
  for i := low(data) to high(data) do
    r[i] := IntToStrU(data[i]);
end;

const
  Count = 10000000;
var
  a: array of LongInt;
  i: SizeInt;
  timer: TEpikTimer;
  e1, e2: Extended;
begin
  Randomize;
  SetLength(a{%H-}, Count);
  for i := low(a) to high(a) do
    a[i] := Random(MaxLongint);
  timer := TEpikTimer.Create(nil);

  timer.Clear;
  timer.Start;
  Test_CP_Conversion(a);
  timer.Stop;
  e1 := timer.Elapsed;
  WriteLn('Test_CP_Conversion: ', timer.ElapsedStr());
 
  timer.Clear;
  timer.Start;
  Test_UTF16_Native(a);
  timer.Stop;
  e2 := timer.Elapsed;
  WriteLn('Test_UTF16_Native : ', timer.ElapsedStr());
  WriteLn('Relation: ', ((e2 / e1)-1)*100 : 4:2, '%');

  FreeAndNil(timer);
  readln;
end.
PascalDragon hat geschrieben:
So 7. Mär 2021, 15:04
Am sinnvollsten ist es aktuell für die Verarbeitung die Strings in UTF-8 umzuwandeln (Typ UTF8String) oder wenn du die LCL verwendest ist das eh die Standardcodepage.
Da ich die LCL derzeit nicht verwende, spielt dies keine Rolle. Ich überlege aber, ob es nicht sinnvoller wäre, die UTF-16 Bibliotheksfunktionen durch UTF-8 Funktionen zu verstecken.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Antworten