はじめに
Goのfmt
パッケージのprintf
系の関数
- Fprintf
- Printf
- Sprintf
のフォーマットの指定方法についてまとめました。
Goでは書式指定子 %...
のことを verb
と表記しています。
すべての型に使えるverb
%v
値のデフォルトのフォーマットでの表現を出力する。
基本型の場合
型 | verb |
---|---|
論理値(bool ) |
%t |
符号付き整数(int , int8 など) |
%d |
符号なし整数(uint , uint8 など) |
%d |
浮動小数点数(float64 など) |
%g |
複素数(complex128 など) |
%g |
文字列(string ) |
%s |
チャネル(chan ) |
%p |
ポインタ(pointer ) |
%p |
package main
import (
"fmt"
)
func main() {
fmt.Printf("%v\n", true)
fmt.Printf("%v\n", 42)
fmt.Printf("%v\n", uint(42))
fmt.Printf("%v\n", 12.345)
fmt.Printf("%v\n", 1-2i)
fmt.Printf("%v\n", "寿司🍣Beer🍺")
fmt.Printf("%v\n", make(chan bool))
fmt.Printf("%v\n", new(int))
}
true
42
42
12.345
(1-2i)
寿司🍣Beer🍺
0x434080
0x416028
コンポジット型の場合
以下のようになり、さらに各要素に対して再帰的に %v
でのフォーマットをしたものが結果として出力される。
型 | フォーマット |
---|---|
構造体(struct ) |
{フィールド1 フィールド2 ...} |
構造体のポインタ | &{フィールド1 フィールド2 ...} |
配列・スライス(array , slice ) |
[要素1 要素2 ...] |
配列・スライスのポインタ | &[要素1 要素2 ...] |
マップ(map ) |
map[キー1:値1 キー2:値2 ...] |
マップのポインタ | &map[キー1:値1 キー2:値2 ...] |
package main
import (
"fmt"
"net/http"
)
func main() {
fmt.Printf("%v\n", http.Client{})
fmt.Printf("%v\n", &http.Client{})
fmt.Printf("%v\n", [...]int{1, 2, 3})
fmt.Printf("%v\n", &[...]int{1, 2, 3})
fmt.Printf("%v\n", []int{1, 2, 3})
fmt.Printf("%v\n", &[]int{1, 2, 3})
fmt.Printf("%v\n", map[string]int{"寿司": 1000, "ビール": 500})
fmt.Printf("%v\n", &map[string]int{"寿司": 1000, "ビール": 500})
}
{<nil> <nil> <nil> 0s}
&{<nil> <nil> <nil> 0s}
[1 2 3]
&[1 2 3]
[1 2 3]
&[1 2 3]
map[寿司:1000 ビール:500]
&map[寿司:1000 ビール:500]
%+v
%v
と同じだが、構造体の場合にフィールド名を出力する。
package main
import (
"fmt"
"net/http"
)
func main() {
fmt.Printf("%v\n", http.Client{})
fmt.Printf("%+v\n", http.Client{})
}
{<nil> <nil> <nil> 0s}
{Transport:<nil> CheckRedirect:<nil> Jar:<nil> Timeout:0s}
%#v
値のGoの文法での表現を出力する。
package main
import (
"fmt"
"net/http"
)
func main() {
fmt.Printf("%#v\n", true)
fmt.Printf("%#v\n", 42)
fmt.Printf("%#v\n", uint(42))
fmt.Printf("%#v\n", 12.345)
fmt.Printf("%#v\n", 1-2i)
fmt.Printf("%#v\n", "寿司🍣Beer🍺")
fmt.Printf("%#v\n", make(chan bool))
fmt.Printf("%#v\n", new(int))
fmt.Printf("\n")
fmt.Printf("%#v\n", http.Client{})
fmt.Printf("%#v\n", &http.Client{})
fmt.Printf("%#v\n", [...]int{1, 2, 3})
fmt.Printf("%#v\n", &[...]int{1, 2, 3})
fmt.Printf("%#v\n", []int{1, 2, 3})
fmt.Printf("%#v\n", &[]int{1, 2, 3})
fmt.Printf("%#v\n", map[string]int{"寿司": 1000, "ビール": 500})
fmt.Printf("%#v\n", &map[string]int{"寿司": 1000, "ビール": 500})
}
true
42
0x2a
12.345
(1-2i)
"寿司🍣Beer🍺"
(chan bool)(0x834100)
(*int)(0x816260)
http.Client{Transport:http.RoundTripper(nil), CheckRedirect:(func(*http.Request, []*http.Request) error)(nil), Jar:http.CookieJar(nil), Timeout:0}
&http.Client{Transport:http.RoundTripper(nil), CheckRedirect:(func(*http.Request, []*http.Request) error)(nil), Jar:http.CookieJar(nil), Timeout:0}
[3]int{1, 2, 3}
&[3]int{1, 2, 3}
[]int{1, 2, 3}
&[]int{1, 2, 3}
map[string]int{"寿司":1000, "ビール":500}
&map[string]int{"寿司":1000, "ビール":500}
%T
値の型のGoの文法での表現を出力する。
package main
import (
"fmt"
"net/http"
)
func main() {
fmt.Printf("%T\n", true)
fmt.Printf("%T\n", 42)
fmt.Printf("%T\n", uint(42))
fmt.Printf("%T\n", 12.345)
fmt.Printf("%T\n", 1-2i)
fmt.Printf("%T\n", "寿司🍣Beer🍺")
fmt.Printf("%T\n", make(chan bool))
fmt.Printf("%T\n", new(int))
fmt.Printf("\n")
fmt.Printf("%T\n", http.Client{})
fmt.Printf("%T\n", &http.Client{})
fmt.Printf("%T\n", [...]int{1, 2, 3})
fmt.Printf("%T\n", &[...]int{1, 2, 3})
fmt.Printf("%T\n", []int{1, 2, 3})
fmt.Printf("%T\n", &[]int{1, 2, 3})
fmt.Printf("%T\n", map[string]int{"寿司": 1000, "ビール": 500})
fmt.Printf("%T\n", &map[string]int{"寿司": 1000, "ビール": 500})
}
bool
int
uint
float64
complex128
string
chan bool
*int
http.Client
*http.Client
[3]int
*[3]int
[]int
*[]int
map[string]int
*map[string]int
%%
%
そのものを出力したい場合に使う。
論理値に使えるverb
%t
true
かfalse
package main
import (
"fmt"
)
func main() {
fmt.Printf("%t\n", true)
fmt.Printf("%t\n", false)
}
true
false
整数に使えるverb
%d
10進数での表現
%b
2進数での表現
%o
8進数での表現
%x
16進数での表現(a-fは小文字)
%X
16進数での表現(A-Fは大文字)
%c
Unicodeコードポイントに対応する文字
%q
対応する文字をシングルクォート'
で囲んだ文字列
package main
import (
"fmt"
)
func main() {
answer := 42
fmt.Printf("%b\n", answer)
fmt.Printf("%c\n", answer)
fmt.Printf("%d\n", answer)
fmt.Printf("%o\n", answer)
fmt.Printf("%q\n", answer)
fmt.Printf("%x\n", answer)
fmt.Printf("%X\n", answer)
fmt.Printf("%U\n", answer)
}
101010
*
42
52
'*'
2a
2A
U+002A
浮動小数点数・複素数に使えるverb
%b
小数点なしの指数表記 指数は2の累乗
%e
指数表記
%E
%e
のe
がE
で表記される
%f
, %F
指数表記なし
%g
指数が大きい場合は%e
そうでなければ%f
%G
指数が大きい場合は%E
そうでなければ%F
package main
import (
"fmt"
)
func main() {
f := 12.345
fmt.Printf("%b\n", f)
fmt.Printf("%e\n", f)
fmt.Printf("%E\n", f)
fmt.Printf("%f\n", f)
fmt.Printf("%F\n", f)
fmt.Printf("%g\n", f)
fmt.Printf("%G\n", f)
fmt.Printf("%g\n", 12345678.9)
fmt.Printf("%G\n", 12345678.9)
}
6949617174986097p-49
1.234500e+01
1.234500E+01
12.345000
12.345000
12.345
12.345
1.23456789e+07
1.23456789E+07
文字列([]byte
も同じ)に使えるverb
%s
そのままの出力
%q
Goの文法上のエスケープをした文字列
%x
1バイトにつき2文字の16進数での表現(a-fは小文字)
%X
%x
と同じだが、A-Fが大文字
package main
import (
"fmt"
)
func main() {
s := "寿司🍣Beer🍺"
fmt.Printf("%s\n", s)
fmt.Printf("%q\n", s)
fmt.Printf("%x\n", s)
fmt.Printf("%X\n", s)
}
寿司🍣Beer🍺
"寿司🍣Beer🍺"
e5afbfe58fb8f09f8da342656572f09f8dba
E5AFBFE58FB8F09F8DA342656572F09F8DBA
width, precision
verbの直前に整数でwidthを指定することができる。
widthはrune
単位で数えられる出力する文字列の長さ。
指定しない場合、値を表現するのに必要な長さになる。
precisionはwidthの直後に.
を付け、その後に整数で指定できる。
.
がない場合、デフォルトのprecisionになる。
.
があるが数値の指定がない場合、precisionは0になる。
width, precisionには整数の代わりに*
を指定することもでき、その場合次の引数の値を指定したことになる。
その場合、その引数の値は整数である必要がある。
-
文字列(
[]byte
でも同じ)の場合: precisionはフォーマット対象にする文字列の長さの上限。文字列が長すぎる場合は途中で切られる。長さはrune
単位だが、%x
か%X
でフォーマットされる場合はバイト単位。 -
浮動小数点数の場合:
- width: 文字列で表現される際の最小の文字数
- precision:
-
%e
,%f
, 小数点以下の桁数 -
%g
,%G
有効桁数の最大値 - デフォルト:
-
%e
,%f
,%#g
: 6 -
%g
: 数値を表すのに必要な桁数
-
-
-
複素数の場合: widthとprecisionの値は実数部と虚数部にそれぞれ適用され、結果は
()
で囲われる。
package main
import (
"fmt"
)
func main() {
f := 12.345
fmt.Printf("%f\n", f)
fmt.Printf("%12f\n", f)
fmt.Printf("%12.2f\n", f)
fmt.Printf("%.2f\n", f)
fmt.Printf("%12.f\n", f)
fmt.Printf("%e\n", f)
fmt.Printf("%#g\n", f)
fmt.Printf("%g\n", f)
fmt.Printf("%f", 1-2i)
}
12.345000
12.345000
12.35
12.35
12
1.234500e+01
12.3450
12.345
(1.000000-2.000000i)
flag
width, precisionの他にもverbの直前に置くことでフォーマットを変えられるflagがあります。
+
- 数値の場合: 正でも符号(+)を出力する
-
%q
の場合: ASCII文字だけで出力する
package main
import (
"fmt"
)
func main() {
fmt.Printf("%d\n", 42)
fmt.Printf("%+d\n", 42)
fmt.Printf("%q\n", 945)
fmt.Printf("%+q\n", 945)
fmt.Printf("%q\n", "寿司🍣Beer🍺")
fmt.Printf("%+q\n", "寿司🍣Beer🍺")
}
42
+42
'α'
'\u03b1'
"寿司🍣Beer🍺"
"\u5bff\u53f8\U0001f363Beer\U0001f37a"
-
左詰めにする
package main
import (
"fmt"
)
func main() {
fmt.Printf("%5d\n", 42)
fmt.Printf("%-5d\n", 42)
fmt.Printf("%10s\n", "寿司🍣Beer🍺")
fmt.Printf("%-10s\n", "寿司🍣Beer🍺")
}
42
42
寿司🍣Beer🍺
寿司🍣Beer🍺
#
デフォルトとは異なるフォーマットにする
- 8進数の場合(
%#o
): 先頭に0を付ける - 16進数の場合(
%#x
): 先頭に0xを付ける - 16進数(大文字)の場合(
%#X
): 先頭に0Xを付ける - ポインタの場合(
%#p
): 先頭の0xを付けない -
%q
の場合:strconv.CanBackquote
がtrueを返すならraw文字列を出力する -
%e
,%E
,%f
,%F
,%g
,%G
の場合: 必ず小数点を付ける -
%g
,%G
の場合: 末尾の0を省略しない -
%U
の場合:U+0078 'x'
の形式で出力する
package main
import (
"fmt"
)
func main() {
answer := 42
fmt.Printf("%o\n", answer)
fmt.Printf("%#o\n", answer)
fmt.Printf("%x\n", answer)
fmt.Printf("%#x\n", answer)
fmt.Printf("%X\n", answer)
fmt.Printf("%#X\n", answer)
fmt.Printf("%p\n", &answer)
fmt.Printf("%#p\n", &answer)
fmt.Printf("%q\n", "go")
fmt.Printf("%#q\n", "go")
fmt.Printf("%q\n", "`go`")
fmt.Printf("%#q\n", "`go`")
fmt.Printf("%.f\n", 12.345)
fmt.Printf("%#.f\n", 12.345)
fmt.Printf("%g\n", 12.345)
fmt.Printf("%#g\n", 12.345)
fmt.Printf("%U\n", answer)
fmt.Printf("%#U\n", answer)
}
52
052
2a
0x2a
2A
0X2A
0x416020
416020
"go"
`go`
"`go`"
"`go`"
12
12.
12.345
12.3450
U+002A
U+002A '*'
(スペース)
- 数値の場合: 符号のためのスペースを空ける
- 文字列をバイト単位で表現する場合: それぞれのバイトの間にスペースを空ける
package main
import (
"fmt"
)
func main() {
fmt.Printf("%d\n", 42)
fmt.Printf("% d\n", 42)
fmt.Printf("%x\n", "寿司🍣Beer🍺")
fmt.Printf("% x\n", "寿司🍣Beer🍺")
fmt.Printf("%X\n", "寿司🍣Beer🍺")
fmt.Printf("% X\n", "寿司🍣Beer🍺")
}
42
42
e5afbfe58fb8f09f8da342656572f09f8dba
e5 af bf e5 8f b8 f0 9f 8d a3 42 65 65 72 f0 9f 8d ba
E5AFBFE58FB8F09F8DA342656572F09F8DBA
E5 AF BF E5 8F B8 F0 9F 8D A3 42 65 65 72 F0 9F 8D BA
0
スペースではなく、0で埋める
数値の場合: 0埋めは符号のあと
package main
import (
"fmt"
)
func main() {
fmt.Printf("%10s\n", "寿司🍣Beer🍺")
fmt.Printf("%010s\n", "寿司🍣Beer🍺")
fmt.Printf("%10.3f\n", -12.345)
fmt.Printf("%010.3f\n", -12.345)
}
寿司🍣Beer🍺
00寿司🍣Beer🍺
-12.345
-00012.345
[n]
引数のインデックス指定
- verbの直前に
[n]
の表記でインデックスを指定することで、フォーマットする引数を指定できる -
*
に対しても使える -
[n]
の指定をした以降はn+1番目, n+2番目, ... となる
package main
import (
"fmt"
)
func main() {
fmt.Printf("%[2]s %[1]s\n", "寿司🍣", "Beer🍺")
fmt.Printf("%[3]*.[2]*[1]f\n", 12.345, 2, 8)
fmt.Printf("%*.*f\n", 8, 2, 12.345)
fmt.Printf("%s %s %[1]q %q", "寿司🍣", "Beer🍺")
}
Beer🍺 寿司🍣
12.35
12.35
寿司🍣 Beer🍺 "寿司🍣" "Beer🍺"