文字列型(Delphi)

提供: RAD Studio
移動先: 案内検索

データ型、変数、定数:インデックス への移動


このトピックでは、Delphi 言語で利用できる文字列データ型について説明します。 次の型について説明します。

文字列型の概要

文字列は、一連の文字を表します。 Delphi では、次の定義済みの文字列型を使用できます。

文字列型

タイプ 最大長 必要なメモリ 用途

ShortString

255 文字

2 ~ 256 バイト

後方互換性

AnsiString

~ 2^31 文字

4 バイト~ 2 GB

8 ビット(ANSI)文字、DBCS ANSI、MBCS ANSI、Unicode 文字など

UnicodeString

メモ: RAD Studio では、文字列は UnicodeString のエイリアスです。

~ 2^30 文字

4 バイト~ 2 GB

Unicode 文字、8 ビット(ANSI)文字、マルチユーザー サーバーおよびマルチ言語アプリケーション

UnicodeString は、デフォルトの文字列型です。

WideString

~ 2^30 文字

4 バイト~ 2 GB

Unicode 文字。マルチユーザー サーバーおよびマルチ言語アプリケーション。 WideString は、モバイル プラットフォーム用 Delphi コンパイラではサポートされていませんが、デスクトップ プラットフォーム用 Delphi コンパイラではサポートされています。UnicodeString の使用は、WideString より推奨されます。

メモ: デフォルトの文字列型は UnicodeString です。WideString は、COM BSTR 型との互換性のために用意されています。一般的には、COM アプリケーション以外に UnicodeString を使用します。 ほとんどの場合、UnicodeString 型の使用をお勧めします。 文字列型は、UnicodeString のエイリアスです。

文字列型は代入や式の中で混在でき、コンパイラは必要な場合に自動的に変換します。 ただし、var および out パラメータとして関数または手続きへの参照渡しが行われる文字列には適切な型を使用する必要があります。 文字列は、別の文字列型に明示的にキャストできます。 ただし、マルチバイト文字列をシングルバイト文字列にキャストすると、データが損失することがあります。

次に、特殊な文字列型について説明します。

  • コード ページの AnsiStrings は次のように定義されます。
Type mystring = type AnsiString(CODEPAGE)
この AnsiString は、特定のコード ページで内部データを管理するのと同様のことを行います。
  • RawByteString 型は、type AnsiString($FFFF) です。 RawByteString を使用すると、コード ページを変換せずに、任意のコード ページの文字列データも渡すことができます。 RawByteString は、const 型または値型のパラメータ、または関数からの戻り値型としてのみ使用します。 参照渡し(var で渡す)は行わないでください。また変数としてインスタンス化しないでください。
  • UTF8String は、UTF-8 でエンコードされた文字列を表します(可変長バイトの Unicode)。 UTF-8 コード ページを持つコード ページの AnsiString 型です。

予約語 string は、一般的な文字列型識別子のように機能します。 例:

var S: string;

これは、文字列を保持する変数 S を作成します。 Win32 プラットフォームで、コンパイラは string(この後に角括弧で囲まれた数字がない場合)を UnicodeString と解釈します。

Win32 プラットフォームでは、{$H-} 指令を使用して stringShortString に変換できます。 これは、現在のプログラムで以前の 16 ビット Delphi コードまたは Turbo Pascal コードを使用している場合などに便利です。

ShortString 型の長さを指定して宣言するときには、キーワード string も使用されることに注意してください(次の ShortString を参照)。

文字列の比較は、対応する位置にある要素の順序値によって定義されます。 長さの異なる文字列間では、短い方の文字列に対応する文字がない、長い方の文字列の各文字が大きい値をとります。 たとえば、'AB' は 'A' より大きいです。つまり、'AB' > 'A' は True を返します。 ゼロ長の文字列は、最小の値を表します。

配列と同様に文字列変数にインデックスを付けることができます。 SUnicodeString 文字列変数ではなく、i が整数型の式ではない場合、S[i]S 内の i 番目のバイトを表し、i 番目の文字または文字全体ではない(マルチバイト文字セットで)可能性があります。 同様に、UnicodeString 変数にインデックスを付けると文字全体ではないことがある要素を表します。 文字列に基本多言語面(BMP)の文字が含まれる場合は、すべての文字は 2 バイトなので、文字列のインデックス化により文字を取得します。 ただし、一部文字が BMP にない場合は、インデックス化要素は、サロゲート ペアの可能性があります。つまり文字全体ではありません。

標準関数 Length は文字列の要素数を返します。 前の説明のとおり、要素数は必ずしも文字数ではありません。 SetLength 手続きは、文字列の長さを調整します。 SizeOf 関数では、変数や型を表現するために使用されるバイト数を返すことに注意してください。 SizeOf では短い文字列に対してのみ、文字列の文字数を返すことに注意してください。 他のすべての文字列型はポインタであるので、SizeOf では文字列に対して、ポインタのバイト数を返します。

短い文字列、つまり AnsiString では、S[i]AnsiChar 型です。 WideString では、S[i]WideChar 型です。 シングルバイト(Western)ロケールの場合、MyString[2]  := 'A';MyString の 2 番目の文字に値 A を代入します。 次のコードは、標準関数 UpCase を使用して MyString を大文字に変換します。

var I: Integer;
begin
  I := Length(MyString);
  while I > 0 do
  begin
    MyString[I] := UpCase(MyString[I]);
    I := I - 1;
  end;
end;

文字列の最後に上書きすることでアクセス違反が起こることがあるため、上記のように文字列にインデックスを付ける場合には注意してください。 また、コードが効率的ではなくなるため、文字列のインデックスを var パラメータで渡さないようにしてください。

文字列定数の値または文字列を返すその他の式を変数に代入できます。 文字列の長さは代入時に動的に変わります。 例:

MyString := 'Hello world!';
MyString := 'Hello' + 'world';
MyString := MyString + '!';
MyString := ' '; { space }
MyString := '';  { empty string }

短い文字列

ShortString は、1 バイト文字 0 ~ 255 個の長さです。 ShortString の長さは動的に変えられますが、メモリ上では静的に 256 バイトが割り当てられます。その最初のバイトに文字列の長さが格納され、残りの 255 バイトに文字を含めることができます。 SShortString 変数である場合、Ord(S[0])Length(S) と同様、S の長さを返します。値を S[0] に代入すると、SetLength を呼び出した場合と同様、S の長さが変わります。 ShortString は下位互換性のためにのみ維持されています。

Delphi 言語では短い文字列型(事実上 ShortString のサブタイプ)をサポートしています。その最大長は 0 ~ 255 文字です。 これは、予約語 string の後に角括弧で囲んだ数字を付けて表します。 例:

var MyString: string[100];

これは最大長が 100 文字の変数 MyString を作成します。 これは次の宣言と同じです。

type CString = string[100];
var MyString: CString;

このように宣言した型には、必要なメモリだけが割り当てられます。つまり、指定した最大長に 1 バイトを加算したメモリが割り当てられます。 定義済みの ShortString 型の変数では 256 バイトが使用されるのに対して、この例の MyString では 101 バイトが使用されます。

型の最大長よりも長い値を ShortString 変数に代入すると、文字列は切り詰められます。

標準関数の HighLow は、短い文字列型の識別子と変数にも使用できます。 High は短い文字列型の最大長を返し、Low はゼロを返します。

AnsiString

AnsiString は、動的に割り当てられた文字列を表します。その最大長の制限は利用可能なメモリによってのみ変わります。

AnsiString の変数の構造は、文字列情報を保持します。 変数が空である場合(つまり、ゼロ長の文字列を含む場合)、ポインタは nil であり、文字列がストレージをさらに使用することはありません。 変数が空ではない場合、文字列値を含む、動的に割り当てられたメモリ ブロックを変数は指しています。 このメモリはヒープに割り当てられますが、その管理は完全に自動化されていて、ユーザー コードは必要ありません。 AnsiString 構造には、32 ビット長の指示子、32 ビットの参照カウント、各文字のバイト数を示す 16 ビットのデータ長、および 16 ビットのコード ページが含まれます。

AnsiString はシングルバイト文字列を表します。 シングルバイト文字セット(SBCS)を使用すると、文字列の各バイトが 1 つの文字を表します。 マルチバイト文字セット(MBCS)では、各要素がシングルバイトでも、1 バイトで表される文字も、1 バイト以上で表される文字もあります。 マルチバイト文字セット、特にダブルバイト文字セット(DBCS)は、アジア言語に広く使用されています。 AnsiString は、MBCS 文字を含んでいる場合があります。

AnsiString のインデックスは 1 から始まります。 S[i]Si 番目のバイト(必ずしも i 番目の文字ではなく)を表すため、マルチバイト文字列のインデックスの信頼性は高くありません。 i 番目のバイトはシングル文字の場合も、文字の一部の場合もあります。 ただし、文字列処理の標準関数 AnsiString にはマルチバイトに対応する同様の関数があり、文字のロケール固有の順序を実装しています。 (通常、マルチバイト関数の名前の先頭には Ansi が付く。 たとえば、マルチバイト版の StrPosAnsiStrPos)。 マルチバイト文字がサポートされているかどうかは、オペレーティング システムや現在のロケールによって異なります。

AnsiString の変数にはポインタがあるため、2 つ以上の長い文字列の変数がさらにメモリを消費せずに同じ値を参照できます。 コンパイラはこれを利用して、リソースを節約して迅速に代入を実行します。 AnsiString の変数が破棄されるか新しい値が代入されると、古い AnsiString(変数の以前の値)の参照カウントはデクリメントされ、新しい値(ある場合)の参照カウントはインクリメントされます。文字列の参照カウントがゼロになると、割り当てられたメモリが解放されます。 これは参照カウント処理と呼ばれます。 インデックスを使用して文字列内の 1 文字の値を変更すると、参照カウントが 1 より大きい場合にのみ文字列のコピーが作成されます。 これをコピーオンライト セマンティクスと呼びます。

UnicodeString(デフォルトの文字列型)

UnicodeString 型は、動的に割り当てられた Unicode 文字列を表します。その最大長の制限は利用可能なメモリによってのみ変わります。

Unicode 文字セットでは、各文字は 1 バイト以上で表されます。 Unicode には複数の Unicode 変換形式があり、互いに簡単に変換できる、異なるが相当の文字エンコードを使用します。

  • たとえば UTF-8 では、文字は 1 ~ 4 バイトです。 UTF-8 では、最初の 128 個の Unicode 文字が US-ASCII 文字にマッピングされます。
  • UTF-16 もよく使用される Unicode エンコードですが、文字は 2 バイトか 4 バイトのどちらかです。 世の中の文字の大多数は基本多言語面(Basic Multilingual Plane)に含まれ、2 バイトで表すことができます。 それ以外の文字には、サロゲート ペアと呼ばれる 2 つの 2 バイト文字が必要です。
  • UTF-32 では各文字を 4 バイトで表します。

Win32 プラットフォームでは、Unicode だけでなくシングルバイト文字セットとマルチバイト文字セットもサポートしています。 Windows オペレーティング システムでは UTF-16 をサポートしています。

詳細は、「Unicode 標準」を参照してください。

UnicodeString 型の構造は、AnsiString 型の構造とまったく同じです。 UnicodeString データは UTF-16 でエンコードされています。

UnicodeStringAnsiString の構造が同じであるため、その機能も非常に似ています。 UnicodeString 変数が空である場合、さらにメモリを消費することはありません。 空でない場合、この変数は、文字列値が格納されている動的割り当てメモリ ブロックを指し、このためのメモリ処理はユーザーには透過的に行われます。 UnicodeString 変数は参照がカウントされず、2 つ以上の変数がさらにメモリを消費せずに同じ値を参照できます。

UnicodeString のインスタンスは文字をインデックス化できます。 インデックス化は 1 からはじまります。AnsiString の場合と同様です。

UnicodeString は他のすべての文字列型と代入のときに互換性があります。 ただし、AnsiStringUnicodeString の間の代入では、適切に変換(拡大や縮小)されます。 UnicodeString 型を AnsiString 型に代入することはお勧めできません。データが失われることがあります。

Delphi では、WideCharPWideChar、および WideString 型を使用して Unicode 文字および Unicode 文字列を使用できます。

Unicode の使用に関する詳細は、「RAD Studio における Unicode」および「アプリケーションを Unicode 対応にする」を参照してください。

WideString

WideString 型は、16 ビット Unicode 文字の動的に割り当てられた文字列を表します。 この型は AnsiString にいくつかの点で似ています。 Win32 では、WideString は COM BSTR 型と互換性があります。

WideString は COM アプリケーションでの使用に適しています。 ただし、WideString では参照がカウントされません。したがって他のタイプのアプリケーションでは UnicodeString がさらに柔軟で効率的です。

S[i]Si 番目の要素(必ずしも i 番目の文字ではない)を表すため、WideString マルチバイト文字列のインデックスの信頼性は高くありません。

Delphi では、Char および PChar 型は、それぞれ WideChar および PWideChar 型となります。

メモ: WideString は、モバイル プラットフォームの Delphi コンパイラではサポートされていませんが、デスクトップ プラットフォームの Delphi コンパイラでは使用されています。

NULL 終端文字列の取り扱い

C や C++ など多くのプログラミング言語には、文字列専用のデータ型がありません。 これらの言語と、それらで構築されている環境は、NULL 終端文字列を利用しています。 NULL 終端文字列は NUL(#0)で終わる文字配列で、インデックスがゼロから始まります。配列には長さを指示する手段がないため、最初の NUL 文字で文字列の終わりを表します。 NULL 終端文字列を使用するシステムとデータを共有する必要がある場合は、Delphi の構文要素と SysUtils ユニット内の特別なルーチン(「標準ルーチンと入出力」を参照)を使用して、NULL 終端文字列を処理できます。

たとえば、以下の型宣言を使用して NULL 終端文字列を格納できます。

type
  TIdentifier = array[0..15] of Char;
  TFileName = array[0..259] of Char;
  TMemoText = array[0..1023] of WideChar;

拡張構文が有効になっている場合({$X+})は、インデックスがゼロで始まる静的に割り当てられた文字配列に文字列定数を代入できます (動的配列はこの目的には役立ちません)。 配列定数を、宣言した配列長よりも短い文字列で初期化する場合、残りの文字は #0 に設定されます。

ポインタ、配列、文字列定数の使用

NULL 終端文字列を操作するには、多くの場合、ポインタを使用する必要があります (「ポインタとポインタ型(Delphi)」を参照)。 文字列定数は、PChar 型および PWideChar 型と代入互換性があり、これらの型は、CharWideChar の値の null 終端配列へのポインタを表します。 例:

var P: PChar;
  ...
P := 'Hello world!'

この場合、P は、元の文字列定数「Hello world!」が格納されているメモリ領域を指します。 これは以下と同等です。

const TempString: array[0..12] of Char = 'Hello world!';
var P: PChar;
   ...
P := @TempString[0];

また、たとえば StrUpper('Hello world!') のように、PChar 型または PWideChar 型の値または const パラメータを取る任意の関数に文字列定数を渡すこともできます。 PChar への代入の場合と同様に、コンパイラは文字列の NULL 終端コピーを生成し、そのコピーを指すポインタを関数に渡します。 最後に、定数 PChar または PWideChar を文字列リテラル(単独または構造型)で初期化することもできます。 例:

const
  Message: PChar = 'Program terminated';
  Prompt: PChar = 'Enter values: ';
  Digits: array[0..9] of PChar =
    ('Zero', 'One', 'Two', 'Three', 'Four', 'Five',
     'Six', 'Seven', 'Eight', 'Nine');

0 始まりの文字配列は、PCharPWideChar と互換性があります。 文字配列をポインタ値の代わりに使用すると、コンパイラはその配列を、配列の先頭要素のアドレスに相当する値を持つポインタ定数に変換します。 例:

var
  MyArray: array[0..32] of Char;
  MyPointer: PChar;
begin
  MyArray := 'Hello';
  MyPointer := MyArray;
  SomeProcedure(MyArray);
  SomeProcedure(MyPointer);
end;

このコードでは、同じ値を渡して SomeProcedure を 2 回呼び出しています。

文字ポインタは、あたかも配列であるかのようにインデックス付けすることができます。 先ほどの例では、MyPointer[0]H を返します。 インデックスは、逆参照の前にポインタに加算されるオフセットを指定します (PWideChar 変数の場合、インデックスは自動的に 2 倍されます。) したがって、P が文字ポインタであれば、P[0]P^ と同等で、配列の 1 文字目を指し、P[1] は配列の 2 文字目を指します(以下同様です)。P[-1]P[0] の左隣の "文字" を指します。 コンパイラでは、これらのインデックスに対して範囲チェックを行いません。

以下の StrUpper 関数では、ポインタのインデックス処理を使用して NULL 終端文字列を 1 文字ずつ処理する例を示しています。

function StrUpper(Dest, Source: PChar; MaxLen: Integer): PChar;
var
  I: Integer;
begin
  I := 0;
  while (I < MaxLen) and (Source[I] <> #0) do
  begin
    Dest[I] := UpCase(Source[I]);
    Inc(I);
  end;
  Dest[I] := #0;
  Result := Dest;
end;

Delphi 文字列と NULL 終端文字列の混在

式や代入で、文字列(AnsiString 値と UnicodeString の)と NULL 終端文字列(PChar 値)を混在でき、PChar 値を文字列パラメータをとる関数や手続きに渡すことができます。 代入 S := PS は文字列変数で PPChar 式)では NULL 終端文字列を文字列にコピーします。

2 項演算では、1 つのオペランドが文字列でもう一方が PChar である場合に、PChar オペランドは UnicodeString に変換されます。

PChar 値を UnicodeString にキャストできます。 これが便利なのは 2 つの PChar 値で文字列演算を実行するときです。 例:

S := string(P1) + string(P2);

UnicodeStringAnsiString 文字列を NULL 終端文字列にキャストすることもできます。 以下のルールが適用されます。

  • SUnicodeString である場合は、PChar(S)S が NULL 終端文字列にキャストされ、S の 1 番目の文字へのポインタが返ります。 このようなキャストは Windows API に使用されます。 たとえば、Str1Str2UnicodeString の場合は、以下のように Win32 API の MessageBox 関数を呼び出すことができます。
    MessageBox(0, PChar(Str1), PChar(Str2), MB_OK);
PAnsiChar(S)SAnsiString である場合)を使用します。
  • Pointer(S) を使用して、文字列を型指定のないポインタにキャストすることもできます。 ただし、S が空の場合、型キャストは nil を返します。
  • PChar(S) は常にメモリ ブロックへのポインタを返します(S が空の場合は、#0 へのポインタが返されます)。
  • UnicodeString または AnsiString の変数をポインタにキャストするときは、変数に新しい値が割り当てられる、またはスコープから外れるまで、ポインタは有効です。 他の任意の文字列式をポインタにキャストする場合、そのポインタは、型キャストが実行されるステートメント内でのみ有効です。
  • UnicodeString または AnsiString の式をポインタにキャストするときは、一般にポインタは読み取り専用とみなされます。 ポインタを使用して安全に文字列を変更できるのは、以下の条件がすべて満たされる場合だけです。
    • 式が UnicodeString または AnsiString 変数にキャストされる。
    • 文字列が空ではない。
    • 文字列が一意(つまり、参照カウントが 1)である。 文字列が固有であることを保証するには、SetLengthSetString または UniqueString の各手続きを呼び出します。
    • 型キャストが行われてからずっと、文字列が変更されていない。
    • 変更される文字がすべて文字列内にある。 ポインタに対して範囲外のインデックスを使用しないように注意してください。

WideString 値と PWideChar 値が混在する場合も同じ規則が適用されます。

長い複数行の文字列リテラル

RAD Studio 12.0 以降、文字列リテラルは現在、255 文字を超えることができるようになりました。つまり、文字列リテラルは従来の Pascal ShortString 型に限定されません。

この言語では、複数行の文字列のサポートが追加されています。 複数行の文字列は三重引用符 (’’’) と新しい行で指定でき、ソース コードの複数行を生成することができ、閉じる三重引用符 (’’’) で終わります。 例:


 const
    strML1 = 
      The quick brown fox jumps
      over the lazy dog.
      ;
    strHTML = 
      <UL>
       <LI>Item 1</LI>
       <LI>Item 2</LI>
       <LI>Item 3</LI>
       <LI>Item 4</LI>
      </UL>
      ;
    strJSON = 
      [
        {"id" : "1", "name" : "Large"},
        {"id" : "2", "name" : "Medium"},
        {"id" : "2", "name" : "Small"}
      ]
      ;
    strSQL= 
      SELECT *
      FROM Customers
      WHERE Department = 'R&D'
      ORDER BY Name;
      ;
 

複数行の文字列のインデントと書式設定ロジックは、非常に具体的に使用されます。複数行の文字列では、先頭の空白が次のように扱われます:

  • 閉じる は、文字列自体の最後の行の末尾ではなく、単独の行に配置する必要があります。
  • 閉じる のインデントによって、文字列全体の基本インデントが決まります。
  • 各行の最終文字列では、そのインデント レベルの前にある空白スペースが削除されます。
  • どの行も基本インデント(閉じる )より小さくインデントすることはできません。これはコンパイラ エラーであり、エラー インサイトとしても表示されます。
  • 閉じる の前の最後の改行は省​​略されます。最後の改行が必要な場合は、最後に空行を追加する必要があります。
メモ: 外部アプリケーションから RAD Studio エディタに複数行のテキストを貼り付ける場合、特殊な非表示文字、制御文字、特定の改行の組み合わせ、および一般的でない Unicode 文字が、エディタを混乱させる可能性がある場合があります。
メモ: 三重引用符 () は、5 や 7 などの大きな奇数の引用符に置き換えることもできます。これにより、複数行の文字列内に実際の三重引用符を埋め込むことができます。例:
 var s := '''''
  some text
  and now '''
  some more text
  ''''';

関連項目