これは何?
書式指定文字列に変なこと書いてもエラーにならない事に気づいて、色々試してみた記録
各種言語の対応
go
この現象を発見したのは go。
fmt.Printf("%d %+d %++d %+++d %++++d\n", 1, 1, 1, 1, 1)
//=> 1 +1 +1 +1 +1
二個以上書いても意味ないけど、エラーにならない。
+
を書ける場所には
も書けるが、意味的に共存できない。
戦わせると
fmt.Printf("[%+d]\n", 1) // [+1]
fmt.Printf("[% d]\n", 1) // [ 1]
fmt.Printf("[%+ +d]\n", 1) // [+1]
fmt.Printf("[% + d]\n", 1) // [+1]
+
が勝つ。
後勝ちだろうと予想していたので、予想が外れた。
ruby
ruby も同様に "%++++++++++++d" % 1
などはエラーにならない。
戦わせてみると
"[+]%+d [ ]% d [+ +]%+ +d [ + ]% + d" % [1,1,1,1]
#=> "[+]+1 [ ] 1 [+ +]+1 [ + ]+1"
go と同じく +
が強い。
python3
python3 も同様に "%++++++++++++d" % 1
などはエラーにならない。
戦わせてみると
"[+]%+d [ ]% d [+ +]%+ +d [ + ]% + d" % (1,1,1,1)
#=> '[+]+1 [ ] 1 [+ +]+1 [ + ]+1'
こちらも +
が強い。
perl
printf("[+]%+d [ ]% d [+ +]%+ +d [ + ]% + d", 1,1,1,1);'
#=> [+]+1 [ ] 1 [+ +]+1 [ + ]+1
こちらも +
が強い。
こんなバグっぽい挙動でみんなの意見が揃うのが気持ち悪い。
PHP
PHP は perl と同じ結果になりやすいという印象がある。
<?php
printf("[+]%+d [ ]% d [+ +]%+ +d [ + ]% + d", 1,1,1,1);
#=> [+]+1 [ ]1 [+ +]+1 [ + ]+1
やはり perl と同じで、つまり +
が強い。
C++
コンパイラによっては警告を出してくれた。
printf("[+]%+d [ ]% d [+ +]%+ +d [ + ]% + d", 1,1,1,1);
//=> warning: flag ' ' is ignored when flag '+' is present [-Wformat]
'+'
があるんで ' '
は無視するよ、という警告で、'+'
が二個あるよ、という警告ではない。
実際、 %++d
や % d
などでは警告は出なかった。
clang と gcc と MSVC を試したけど、みんな go と同じく +
が強く、-
が弱い。
ここまで揃っていると仕様があるのかなと思ったりするけど調べてない。
Java
Java はエラーにしそうだなと予想していた。
System.out.printf("%++d", 1);
//=> Exception in thread "main" java.util.DuplicateFormatFlagsException: Flags = '+'
やはりエラー。そういう人だよね。
wsprintf (Windows)
MSDN には「もう使わないで」と書いてあるけど wsprintf
は今でも使える。
この関数は
- 書き込まれるバッファは 1024 バイト固定
-
%f
がない
などの特徴がある気持ち悪い関数で、こいつなら他と違う挙動になるかと思ったんだけど、そもそも +
などのフラグがなかった。残念。
%##########x
や %000000000d
のような無駄な指定がエラーにならないのは go などと同様だったんだけど、
と +
のような戦いはできないのであった。
まとめ
C 言語に由来すると思われる
"%d"
のような書式文字列に
"++++++++++%d"
のようなことを書いても意味がないわけだけど、 Java 以外はエラーにしない。
それと、この +
と
を戦わせると、みんな +
の勝ちだった。不思議。
普通に書いたら後勝ちになりそうなものだと想像していたんだけれど。
思いつく限りの言語で試したんだけど、他に C の printf
と同じような書式文字列が使える 言語 / ライブラリ ってなんかあったっけ。