Ich versuche, Ersatzpaare und Unicode-Implementierung in Delphi besser zu verstehen.
Lassen Sie uns einige Begriffe aus dem Weg räumen.
jedes „Zeichen“ (auch bekannt als Graphem), die von Unicode definiert ist, wird eine einzigartige Codepunkt zugeordnet.
In einer Unicode Transformation Format (UTF) Kodierung - UTF-7, UTF-8, UTF-16 und UTF-32 - jeder Codepunkt wird als eine Folge von kodierten Codeunits. Die Größe jeder Codeeinheit wird durch die Codierung bestimmt - 7 Bits für UTF-7, 8 Bits für UTF-8, 16 Bits für UTF-16 und 32 Bits für UTF-32 (daher deren Namen).
In Delphi 2009 und später ist String
ein Alias für UnicodeString
, und Char
ist ein Alias für WideChar
. WideChar
ist 16 Bits. A UnicodeString
enthält eine codierte Zeichenfolge UTF-16 (in früheren Versionen von Delphi war der entsprechende Zeichenfolientyp WideString
) und jede WideChar
ist eine UTF-16-Codeeinheit.
In UTF-16 kann ein Codepunkt mit 1 oder 2 Codeeinheiten codiert werden. Eine Codeeinheit kann Codepunktwerte im BMP-Bereich (Basic Multilingual Plane) codieren - $ 0000 bis einschließlich $ FFFF. Höhere Codepunkte erfordern 2 Codeeinheiten, die auch als Ersatzpaar bezeichnet werden.
Wenn ich Länge() aufrufen, auf der Unicode-String S: = 'haben' in Delphi, ich werde zurückkommen, 8.
Dies liegt daran, die Längen der einzelnen Zeichen [H], [ à], [V] und [e] sind 2, 3, 2 bzw. 1.
Dies ist, weil Ĥ ein Ersatz hat, has hat zwei zusätzliche Surrogate, V hat ein Surrogat und e hat keine Surrogate.
Ja, gibt es 8 WideChar
Elemente (Codeunits) im UTF-16 UnicodeString
. Was Sie "Surrogate" nennen, nennt man eigentlich "Kombinationszeichen". Jede Kombinationsmarkierung ist ihr eigener eindeutiger Codepunkt und somit ihre eigene Codeeinheitssequenz.
Wenn ich das zweite Element in der Zeichenfolge einschließlich aller Ersatzzeichen zurückgeben wollte, [à], wie würde ich das tun?
Sie haben zu Beginn des UnicodeString
starten und jedes WideChar
analysieren, bis Sie einen finden, der nicht ein Kombinationszeichen zu einem früheren WideChar
angebracht ist. Unter Windows ist der einfachste Weg, dies zu tun, um die CharNextW()
Funktion, zB zu verwenden:
var
S: String;
P: PChar;
begin
S := 'Ĥà̲V̂e';
P := CharNext(PChar(S)); // returns a pointer to à̲
end;
Das Delphi-RTL keine entsprechende Funktion hat. Sie würden einen manuell schreiben oder eine Bibliothek eines Drittanbieters verwenden. Die RTL hat eine StrNextChar()
Funktion, aber es behandelt nur UTF-16-Surrogate, keine Kombination von Marken (CharNext()
behandelt beide). So konnten Sie StrNextChar()
verwenden, um durch jeden Codepunkt in der UnicodeString
zu scannen, aber man muss bei jedem Codepunkt loo wissen, ob es sich um eine Kombination von Zeichen ist oder nicht, zum Beispiel:
uses
Character;
function MyCharNext(P: PChar): PChar;
begin
if (P <> nil) and (P^ <> #0) then
begin
Result := StrNextChar(P);
while GetUnicodeCategory(Result^) = ucCombiningMark do
Result := StrNextChar(Result);
end else begin
Result := nil;
end;
end;
var
S: String;
P: PChar;
begin
S := 'Ĥà̲V̂e';
P := MyCharNext(PChar(S)); // should return a pointer to à̲
end;
Ich weiß, dass ich brauchen würde um die einzelnen Bytes zu testen.
Nicht die Bytes, aber die Codepoints, dass sie, wenn dekodiert darstellen.
lief ich ein paar Tests, um die Routine
Funktion GetFirstCodepointSize (const S: UTF8String): mit Integer
Schauen Sie genau in dieser Funktion Unterschrift. Siehe den Parametertyp? Es ist eine UTF-8 Zeichenfolge, keine UTF-16 Zeichenfolge. Dies wurde auch in der Antwort angegeben Sie diese Funktion aus bekam:
Hier ist ein Beispiel, wie man analysieren UTF8 String
UTF8 und UTF-16 sind sehr unterschiedliche Kodierungen und damit haben unterschiedliche Semantiken. Sie können UTF-8-Semantik nicht verwenden, um eine UTF-16-Zeichenfolge zu verarbeiten und umgekehrt.
Gibt es einen zuverlässigen Weg in Delphi zu bestimmen, wo ein Element in einer Unicode-Zeichenfolge beginnt und endet?
Nicht direkt. Sie müssen die Zeichenfolge von Anfang an analysieren und Elemente nach Bedarf überspringen, bis Sie das gewünschte Element erreicht haben. Denken Sie daran, dass jeder Codepunkt als 1 oder 2 Codeeinheitselemente codiert sein kann und jedes logische Symbol unter Verwendung mehrerer Codepunkte (und somit mehrerer Codeeinheitsequenzen) codiert sein kann.
Ich weiß, meine Terminologie mit dem Wort Element kann aus sein, aber ich glaube nicht, Codepoint und Zeichen sind entweder richtig, vor allem gegeben, dass ein Element eine Codepoint-Größe von 3 haben kann, aber nur eine Länge von ein.
1 Glyphe besteht aus 1 + Codepoints, und jeder Codepunkt ist als 1+ Codeunits codiert.
Kann jemand die folgende Funktion implementieren?
Funktion GetElementAtIndex (S: String; StrIdx: Integer): String;
so etwas wie dieses Versuchen:
uses
SysUtils, Character;
function MyCharNext(P: PChar): PChar;
begin
Result := P;
if Result <> nil then
begin
Result := StrNextChar(Result);
while GetUnicodeCategory(Result^) = ucCombiningMark do
Result := StrNextChar(Result);
end;
end;
function GetElementAtIndex(S: String; StrIdx : Integer): String;
var
pStart, pEnd: PChar;
begin
Result := '';
if (S = '') or (StrIdx < 0) then Exit;
pStart := PChar(S);
while StrIdx > 1 do
begin
pStart := MyCharNext(pStart);
if pStart^ = #0 then Exit;
Dec(StrIdx);
end;
pEnd := MyCharNext(pStart);
{$POINTERMATH ON}
SetString(Result, pStart, pEnd-pStart);
end;
* Könnte jemand die folgende Funktion implementieren * Dies ist kein Schreiben von Code-Dienst ist, wo Sie Ihre Anforderungen und jemand schreiben churns den Code aus, sie zu treffen?. Bemühen Sie sich, es selbst zu schreiben. Wenn Sie Probleme haben, schreiben Sie den Code, den Sie geschrieben haben, erklären Sie, wie es nicht wie erwartet funktioniert, und stellen Sie eine ** spezifische Frage ** zu diesem Code, und wir können versuchen, Ihnen zu helfen. * Bitte gib mir den Code * ist keine gültige Frage hier. –