Length
文字列を配列と見なした場合の要素数を返します。
- 8 ビット要素タイプ (ANSI、UTF-8) の文字列
Length
の場合、バイト数は要素数と同じであるため、バイト数が得られます。
- 16 ビット要素 (UTF-16) を持つ文字列の場合
Length
、各要素が 2 バイト幅であるため、バイト数は半分になります。
文字列 '1¢' には 2 つのコード ポイントがありますが、2 番目のコード ポイントを UTF-8 でエンコードするには 2 バイトが必要です。したがってLength(Utf8String('1¢'))
、3 に評価されます。
SizeOf
あなたは質問のタイトルに言及しています。文字列変数を に渡すと、SizeOf
常にポインターのサイズが返されます。これは、文字列変数は内部的には単なるポインターであるためです。
あなたの特定の質問に:
ハンドリングに違いがあるのはなぜですか?
Length
バイトに関連すると考える場合にのみ違いがあります。しかし、それは常に要素数を返すと考えるのは間違った方法Length
です。そのように見ると、すべての文字列型、実際にはすべての配列型で動作が均一です。
Length() が期待どおりに動作せず、場合によってはサイズをバイト単位で指定するのではなく、パラメーターの長さ (要素の数など) だけを返すのはなぜですか?
常に要素数を返します。要素のサイズが 1 バイトの場合、要素の数とバイトの数がたまたま同じになることがあります。実際、参照しているドキュメントには、提供した抜粋のすぐ上に次の記述も含まれています。文字列内の文字数または配列内の要素数を返します。それがキーテキストです。あなたが含めた抜粋は、このイタリック体のテキストの意味を説明するためのものです。
Unicode (UTF-16) 文字列の結果を 2 で除算すると述べているのはなぜですか? AFAIK UTF-16 は最大で 4 バイトであるため、これにより誤った結果が得られます。
UTF-16 文字要素は常に 16 ビット幅です。ただし、一部の Unicode コード ポイントでは、エンコードに 2 つの文字要素が必要です。これらの文字要素のペアは、サロゲート ペアと呼ばれます。
Length
文字列内のコードポイントの数を返すことを望んでいると思います。しかし、そうではありません。文字要素の数を返します。また、可変長エンコーディングの場合、コード ポイントの数は必ずしも文字要素の数と同じではありません。文字列が UTF-32 としてエンコードされている場合、UTF-32 は一定サイズのエンコードであるため、コード ポイントの数は文字要素の数と同じになります。
コード ポイントをカウントする簡単な方法は、文字列をスキャンしてサロゲート ペアをチェックすることです。サロゲート ペアに遭遇したら、1 つのコード ポイントを数えます。それ以外の場合、サロゲート ペアの一部ではない文字要素に遭遇した場合は、1 つのコード ポイントを数えます。擬似コード:
N := 0;
for C in S do
if C.IsSurrogate then
inc(N)
else
inc(N, 2);
CodePointCount := N div 2;
もう 1 つの注意点は、コード ポイント数が表示可能な文字数と同じではないということです。一部のコード ポイントは結合文字であり、隣接するコード ポイントと結合されて、1 つの可視文字またはグリフを形成します。
最後に、文字列ペイロードのバイト サイズを確認することだけが目的の場合は、次の式を使用します。
Length(S) * SizeOf(S[1])
この式は、すべてのタイプの文字列で機能します。
関数には十分注意してくださいSystem.SysUtils.ByteLength
。一見すると、これはまさにあなたが望むもののようです。ただし、その関数は UTF-16 でエンコードされた文字列のバイト長を返します。したがってAnsiString
、たとえば を渡すと、 によって返される値はByteLength
のバイト数の 2 倍になりますAnsiString
。