D言語のwritef
とprintf
とは少し違う
D言語のwritef
は、C言語のprintf
と同じもので
書式指定子は全く同じと思っていたのですが、
違うところがあるようなので、簡単に調べてみました。
書式指定子についての説明は、writef
が内部的に
呼び出しているformattedWrite
のドキュメント
に書いてあります。内容をざっくりと要約すると
- 基本は
printf
の書式指定子を踏襲 -
%s
は文字列ではなく型のプレースホルダ -
%(
と%)
で囲むと、配列の要素を順に表示できる
%s
は文字列ではなく型のプレースホルダ
迷ったら、とりあえず%s
にしておけばOK!
型に合わせて、適切に処理してくれます。
ユーザー定義型の場合、toString()
メソッドが呼ばれます。
struct Hoge { string toString() { return "hoge"; } }
void main()
{
import std.stdio, std.math;
int n = 123;
real r = PI;
string s = "hello";
Hoge h;
writef("%s, %s(%.11s), %s, %s", n, r, r, s, h);
}
123, 3.14159(3.1415926536), hello, hoge
%(
と%)
で囲むと、配列の要素を順に表示できる
%(
と%)
の間に配列を指定すると、全ての要素を順に表示してくれます。
void main()
{
import std.stdio;
int[] arr = [0, 1, 2, 3, 4];
writef("%s", arr);
writef("%(%s %)", arr);
}
[0, 1, 2, 3, 4]
0 1 2 3 4
要素%s
と%)
との間の内容は、暗黙的に__区切り文字__として扱われます。
上の例では、半角スペースが区切り文字です。
区切り文字は、__要素間にのみ挿入__され、末尾要素の後ろには挿入されません。
writef("%(%s, %)", arr);
0, 1, 2, 3, 4
区切り文字は,
(カンマと半角スペース)で、
「4」の後ろには挿入されていません。
文字や文字列の配列を表示する場合、'
や"
が表示されますが、__%-(
でエスケープ__できます。
char[] cs = ['a', 'b', 'c', 'd'];
string[] ss = ["hoge", "fuga", "piyo"];
writefln("%s / %s", cs, ss);
writefln("%(%s,%) / %(%s,%)", cs, ss);
writefln("%-(%s,%) / %-(%s,%)", cs, ss);
abcd / ["hoge", "fuga", "piyo"]
'a','b','c','d' / "hoge","fuga","piyo"
a,b,c,d / hoge,fuga,piyo
更に、__多次元配列(ネストした配列)を表示することも可能__です。
int[][] mat = [[0, 1], [2, 3], [4, 5]];
writef("%(%(%s %)\n%)", mat);
}
0 1
2 3
4 5
内側の配列(int[]
)の区切り文字が半角スペースで、
外側の配列(int[][]
)の区切り文字が\n
(改行)です。
非常に便利です!
ですが、区切り文字をカスタマイズしたい時があります。
例えば、括弧、スペース、改行で、いい感じにインデントを揃えたい時に
writef("(%([%(%s %)]\n %))", mat);
([0 1]
[2 3]
[4 5)
いい感じなのですが、末尾の]
が抜けました。
これは、]
が暗黙的な区切り文字に含まれていたために、
末尾要素の後ろに挿入されなかったためです。
こんな場合に、__明示的に区切り文字を指定__できる%|
(※Lではなく縦線)があります。
__%|【区切り文字】
__のように使用します。
writef("(%([%(%s %)]%|\n %))", mat);
([0 1]
[2 3]
[4 5])
上の例では、区切り文字を明示的に\n
(改行と半角スペース)としたことで、
]
を区切り文字から除外でき、意図した通り表示されました。
その他
その他にもbool型などは、%s
だとtrue/falseで表示され、%b
だと1/0で表示されるなど、
細かくは色々あると思うのですが、詳しくは元のドキュメントに当たってください。