D の文字列は自身の長さを認識していたり, ただの文字の配列であったりするなど, C の文字列とは大きな違いがある.
二重引用符文字列:
"hogo"
"Hoge" "Hoge" // 連結される
WYSIWYG 文字列 (r”“で囲むとエスケープシーケンスが使えず, そのままの文字として扱われる):
r"c:\windows"
バッククォート (`) で囲んでも同じだが ” が使える:
`<a href="http://www.apple.com">
Apple Corp.
</a>`
デリミタ指定文字列 (下記のいずれかが使える):
q"()"
q"[]"
q"<>"
q"{}"
トークン文字列 (D のトークンとして正しいものだけを記述できる. コメントも文字列になる):
q{ foo } // "foo"
q{ /+}+/ } // "/+}+/"
D は 3 種類の文字コードの文字列を組み込みで持っている.
str_code.d
1 2 3 4 5 6 7 8 9 10 11 12 13 | import std.stdio;
void main(){
string a = "hello"; // "hello"c
wstring b = "HeLLo"; // "HeLLo"w
dstring c = "HELLO"; // "HELLO"d
writeln(a, " ", b, " ", c);
writefln("a.length = %d", a.length);
writefln("b.length = %d", b.length);
writefln("c.length = %d", c.length);
}
|
str_code.d の実行結果は:
[cactus:~/code_d/d_tuts]% ./str_code
hello HeLLo HELLO
a.length = 5
b.length = 5
c.length = 5
文字列リテラルの型を明示するときは次の postfix を付ける.
文字列の長さは .length プロパティで取得
今まで何度も使ってきた string は, 実は, immutable(char)[] の alias であるため, 次の 2 行は同じ意味である:
string a = "hoge";
immutable(char)[] a = "hoge";
D の文字列は, ただの文字の配列なので, 配列に対して行える操作のほとんどがそのまま行える.
str_array.d
1 2 3 4 5 6 7 8 9 10 11 | import std.stdio;
void main(){
char[] a = "japan".dup;
a ~= "ese";
a[0..1] = "J";
writeln(a);
}
|
str_array.d の実行結果は:
[cactus:~/code_d/d_tuts]% ./str_array
Japanese
D の文字列は char, wchar, dchar の (書き換え可能, immutable, const のいずれかの) 配列
immutable(char)[] 型である文字列リテラルを char[] 型の変数で受け取ることはできないので, .dup で char[] 型のコピーを作る必要がある.
D では char[] を immutable(char)[] に代入することができないので, copy-on-write がタイプシステムによって強制され保証される.
これによって, 文字列のコピーの無駄が少なくなる.
str_copy.d
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import std.stdio;
void main(){
string a = "hoge";
string b;
b = a; // シャローコピー (参照だけをコピーするので実体は同じものを指している)
char[] c = a.dup; // .dup プロパティでディープコピー (別の実体を作成してそれを参照)
char[] d = c; // シャローコピー (参照だけをコピー)
c[0] = 'H';
writeln(a);
writeln(b);
writeln(c);
writeln(d);
}
|
str_copy.d の実行結果は:
[cactus:~/code_d/d_tuts]% ./str_copy
hoge
hoge
Hoge
Hoge
c[0] への代入の結果が同じ実体を参照している d には 影響しているが, 別の実体を持つ a と b には影響していない.
D 言語の配列 (文字列を含む) は参照型
同じ文字列を参照する複数の変数の 一つから文字列を書き換えると, 他のすべての変数の文字列も書き換わる.
普段は string を使い, 書き換え可能な文字列が欲しいときに .dup プロパティでディープコピーする. char[] は immutable(char)[] に代入できないので copy-on-write がタイプシステムによって保証される.
逆に, 書き換え可能な配列から immutable な配列を作るために, .idup プロパティを用いて immutable 型のコピーを作ることができる:
char[] s = "hoge".dup;
immutable(char)[] t = s.idup;
cfunc_d.d
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | import std.stdio;
import std.string;
void cFunc(const char* s){ // C の関数
std.stdio.printf("%s\n", s);
}
void main(){
{
// 方法1: 標準ライブラリを使う
string dstr = "hoge";
const char* cstr = std.string.toStringz(dstr);
cFunc(cstr);
}
{
// 方法2: '\0' を末尾に追加してから char* にキャストする
string dstr = "hoge";
const char* cstr = cast(char*)(dstr ~ '\0');
cFunc(cstr);
}
{
// 方法3: '\0' を末尾に追加してから .ptr プロパティを使う
string dstr = "hoge";
const char* cstr = (dstr ~ '\0').ptr;
cFunc(cstr);
}
}
|
cfunc_d.d の実行結果は:
[cactus:~/code_d/d_tuts]% ./cfunc_d
hoge
hoge
hoge