mirror of
https://github.com/golang/go
synced 2024-11-21 16:14:42 -07:00
fmt: support '*' for width or precision
R=r CC=golang-dev https://golang.org/cl/2237044
This commit is contained in:
parent
b7cb844ac8
commit
176364900e
@ -47,7 +47,9 @@
|
||||
number of places after the decimal, if appropriate. The
|
||||
format %6.2f prints 123.45. The width of a field is the number
|
||||
of Unicode code points in the string. This differs from C's printf where
|
||||
the field width is the number of bytes.
|
||||
the field width is the number of bytes. Either or both of the
|
||||
flags may be replaced with the character '*', causing their values
|
||||
to be obtained from the next operand, which must be of type int.
|
||||
|
||||
Other flags:
|
||||
+ always print a sign for numeric values
|
||||
|
@ -605,3 +605,45 @@ func TestFormatterPrintln(t *testing.T) {
|
||||
t.Errorf("Sprintf wrong with Formatter: expected %q got %q\n", expect, s)
|
||||
}
|
||||
}
|
||||
|
||||
func args(a ...interface{}) []interface{} { return a }
|
||||
|
||||
type starTest struct {
|
||||
fmt string
|
||||
in []interface{}
|
||||
out string
|
||||
}
|
||||
|
||||
var startests = []starTest{
|
||||
starTest{"%*d", args(4, 42), " 42"},
|
||||
starTest{"%.*d", args(4, 42), "0042"},
|
||||
starTest{"%*.*d", args(8, 4, 42), " 0042"},
|
||||
starTest{"%0*d", args(4, 42), "0042"},
|
||||
starTest{"%-*d", args(4, 42), "42 "},
|
||||
|
||||
// erroneous
|
||||
starTest{"%*d", args(nil, 42), "%(badwidth)42"},
|
||||
starTest{"%.*d", args(nil, 42), "%(badprec)42"},
|
||||
starTest{"%*d", args(5, "foo"), "%d(string= foo)"},
|
||||
starTest{"%*% %d", args(20, 5), "% 5"},
|
||||
starTest{"%*", args(4), "%(badwidth)%*(int=4)"},
|
||||
starTest{"%*d", args(int32(4), 42), "%(badwidth)42"},
|
||||
}
|
||||
|
||||
// TODO: there's no conversion from []T to ...T, but we can fake it. These
|
||||
// functions do the faking. We index the table by the length of the param list.
|
||||
var sprintf = []func(string, []interface{}) string{
|
||||
0: func(f string, i []interface{}) string { return Sprintf(f) },
|
||||
1: func(f string, i []interface{}) string { return Sprintf(f, i[0]) },
|
||||
2: func(f string, i []interface{}) string { return Sprintf(f, i[0], i[1]) },
|
||||
3: func(f string, i []interface{}) string { return Sprintf(f, i[0], i[1], i[2]) },
|
||||
}
|
||||
|
||||
func TestWidthAndPrecision(t *testing.T) {
|
||||
for _, tt := range startests {
|
||||
s := sprintf[len(tt.in)](tt.fmt, tt.in)
|
||||
if s != tt.out {
|
||||
t.Errorf("got %q expected %q", s, tt.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ var (
|
||||
extraBytes = []byte("?(extra ")
|
||||
irparenBytes = []byte("i)")
|
||||
bytesBytes = []byte("[]byte{")
|
||||
widthBytes = []byte("%(badwidth)")
|
||||
precBytes = []byte("%(badprec)")
|
||||
)
|
||||
|
||||
// State represents the printer state passed to custom formatters.
|
||||
@ -782,6 +784,16 @@ BigSwitch:
|
||||
return false
|
||||
}
|
||||
|
||||
// intFromArg gets the fieldnumth element of a. On return, isInt reports whether the argument has type int.
|
||||
func intFromArg(a []interface{}, end, i, fieldnum int) (num int, isInt bool, newi, newfieldnum int) {
|
||||
newi, newfieldnum = end, fieldnum
|
||||
if i < end && fieldnum < len(a) {
|
||||
num, isInt = a[fieldnum].(int)
|
||||
newi, newfieldnum = i+1, fieldnum+1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (p *pp) doPrintf(format string, a []interface{}) {
|
||||
end := len(format) - 1
|
||||
fieldnum := 0 // we process one field per non-trivial format
|
||||
@ -816,11 +828,25 @@ func (p *pp) doPrintf(format string, a []interface{}) {
|
||||
break F
|
||||
}
|
||||
}
|
||||
// do we have 20 (width)?
|
||||
p.fmt.wid, p.fmt.widPresent, i = parsenum(format, i, end)
|
||||
// do we have .20 (precision)?
|
||||
// do we have width?
|
||||
if format[i] == '*' {
|
||||
p.fmt.wid, p.fmt.widPresent, i, fieldnum = intFromArg(a, end, i, fieldnum)
|
||||
if !p.fmt.widPresent {
|
||||
p.buf.Write(widthBytes)
|
||||
}
|
||||
} else {
|
||||
p.fmt.wid, p.fmt.widPresent, i = parsenum(format, i, end)
|
||||
}
|
||||
// do we have precision?
|
||||
if i < end && format[i] == '.' {
|
||||
p.fmt.prec, p.fmt.precPresent, i = parsenum(format, i+1, end)
|
||||
if format[i+1] == '*' {
|
||||
p.fmt.prec, p.fmt.precPresent, i, fieldnum = intFromArg(a, end, i+1, fieldnum)
|
||||
if !p.fmt.precPresent {
|
||||
p.buf.Write(precBytes)
|
||||
}
|
||||
} else {
|
||||
p.fmt.prec, p.fmt.precPresent, i = parsenum(format, i+1, end)
|
||||
}
|
||||
}
|
||||
c, w = utf8.DecodeRuneInString(format[i:])
|
||||
i += w
|
||||
|
@ -289,8 +289,6 @@ var s, t string
|
||||
var c complex
|
||||
var x, y Xs
|
||||
|
||||
func args(a ...interface{}) []interface{} { return a }
|
||||
|
||||
var multiTests = []ScanfMultiTest{
|
||||
ScanfMultiTest{"", "", nil, nil, ""},
|
||||
ScanfMultiTest{"%d", "23", args(&i), args(23), ""},
|
||||
|
Loading…
Reference in New Issue
Block a user