mirror of
https://github.com/golang/go
synced 2024-11-25 16:07:56 -07:00
fmt: debugging formats for characters: %+q %#U
%+q uses strconv.Quote[Rune]ToASCII, guaranteeing ASCII-only output. %#U a quoted character if the rune is printable: 'x'=U+0078; otherwise it's as before: U+000A. R=golang-dev, gri, rsc CC=golang-dev https://golang.org/cl/4589047
This commit is contained in:
parent
4b1170d2b1
commit
d152fe74e1
@ -63,11 +63,13 @@
|
|||||||
number of characters to output, truncating if necessary.
|
number of characters to output, truncating if necessary.
|
||||||
|
|
||||||
Other flags:
|
Other flags:
|
||||||
+ always print a sign for numeric values
|
+ always print a sign for numeric values;
|
||||||
|
guarantee ASCII-only output for %q (%+q)
|
||||||
- pad with spaces on the right rather than the left (left-justify the field)
|
- pad with spaces on the right rather than the left (left-justify the field)
|
||||||
# alternate format: add leading 0 for octal (%#o), 0x for hex (%#x);
|
# alternate format: add leading 0 for octal (%#o), 0x for hex (%#x);
|
||||||
0X for hex (%#X); suppress 0x for %p (%#p);
|
0X for hex (%#X); suppress 0x for %p (%#p);
|
||||||
print a raw (backquoted) string if possible for %q (%#q)
|
print a raw (backquoted) string if possible for %q (%#q);
|
||||||
|
write e.g. U+0078 'x' if the character is printable for %U (%#U).
|
||||||
' ' (space) leave a space for elided sign in numbers (% d);
|
' ' (space) leave a space for elided sign in numbers (% d);
|
||||||
put spaces between bytes printing strings or slices in hex (% x, % X)
|
put spaces between bytes printing strings or slices in hex (% x, % X)
|
||||||
0 pad with leading zeros rather than spaces
|
0 pad with leading zeros rather than spaces
|
||||||
|
@ -133,6 +133,7 @@ var fmttests = []struct {
|
|||||||
{"%q", "\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`},
|
{"%q", "\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`},
|
||||||
{"%q", "abc\xffdef", `"abc\xffdef"`},
|
{"%q", "abc\xffdef", `"abc\xffdef"`},
|
||||||
{"%q", "\u263a", `"☺"`},
|
{"%q", "\u263a", `"☺"`},
|
||||||
|
{"%+q", "\u263a", `"\u263a"`},
|
||||||
{"%q", "\U0010ffff", `"\U0010ffff"`},
|
{"%q", "\U0010ffff", `"\U0010ffff"`},
|
||||||
|
|
||||||
// escaped characters
|
// escaped characters
|
||||||
@ -145,6 +146,8 @@ var fmttests = []struct {
|
|||||||
{"%q", uint64(0xFFFFFFFF), `%!q(uint64=4294967295)`},
|
{"%q", uint64(0xFFFFFFFF), `%!q(uint64=4294967295)`},
|
||||||
{"%q", '"', `'"'`},
|
{"%q", '"', `'"'`},
|
||||||
{"%q", '\'', `'\''`},
|
{"%q", '\'', `'\''`},
|
||||||
|
{"%q", "\u263a", `"☺"`},
|
||||||
|
{"%+q", "\u263a", `"\u263a"`},
|
||||||
|
|
||||||
// width
|
// width
|
||||||
{"%5s", "abc", " abc"},
|
{"%5s", "abc", " abc"},
|
||||||
@ -187,6 +190,12 @@ var fmttests = []struct {
|
|||||||
{"%U", 0x12345, "U+12345"},
|
{"%U", 0x12345, "U+12345"},
|
||||||
{"%10.6U", 0xABC, " U+000ABC"},
|
{"%10.6U", 0xABC, " U+000ABC"},
|
||||||
{"%-10.6U", 0xABC, "U+000ABC "},
|
{"%-10.6U", 0xABC, "U+000ABC "},
|
||||||
|
{"%U", '\n', `U+000A`},
|
||||||
|
{"%#U", '\n', `U+000A`},
|
||||||
|
{"%U", 'x', `U+0078`},
|
||||||
|
{"%#U", 'x', `U+0078 'x'`},
|
||||||
|
{"%U", '\u263a', `U+263A`},
|
||||||
|
{"%#U", '\u263a', `U+263A '☺'`},
|
||||||
|
|
||||||
// floats
|
// floats
|
||||||
{"%+.3e", 0.0, "+0.000e+00"},
|
{"%+.3e", 0.0, "+0.000e+00"},
|
||||||
|
@ -7,6 +7,7 @@ package fmt
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"unicode"
|
||||||
"utf8"
|
"utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -50,6 +51,7 @@ type fmt struct {
|
|||||||
sharp bool
|
sharp bool
|
||||||
space bool
|
space bool
|
||||||
unicode bool
|
unicode bool
|
||||||
|
uniQuote bool // Use 'x'= prefix for %U if printable.
|
||||||
zero bool
|
zero bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,6 +65,7 @@ func (f *fmt) clearflags() {
|
|||||||
f.sharp = false
|
f.sharp = false
|
||||||
f.space = false
|
f.space = false
|
||||||
f.unicode = false
|
f.unicode = false
|
||||||
|
f.uniQuote = false
|
||||||
f.zero = false
|
f.zero = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,6 +235,24 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
|
|||||||
i--
|
i--
|
||||||
buf[i] = ' '
|
buf[i] = ' '
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we want a quoted char for %#U, move the data up to make room.
|
||||||
|
if f.unicode && f.uniQuote && a >= 0 && a <= unicode.MaxRune && unicode.IsPrint(int(a)) {
|
||||||
|
runeWidth := utf8.RuneLen(int(a))
|
||||||
|
width := 1 + 1 + runeWidth + 1 // space, quote, rune, quote
|
||||||
|
copy(buf[i-width:], buf[i:]) // guaranteed to have enough room.
|
||||||
|
i -= width
|
||||||
|
// Now put " 'x'" at the end.
|
||||||
|
j := len(buf) - width
|
||||||
|
buf[j] = ' '
|
||||||
|
j++
|
||||||
|
buf[j] = '\''
|
||||||
|
j++
|
||||||
|
utf8.EncodeRune(buf[j:], int(a))
|
||||||
|
j += runeWidth
|
||||||
|
buf[j] = '\''
|
||||||
|
}
|
||||||
|
|
||||||
f.pad(buf[i:])
|
f.pad(buf[i:])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,7 +312,11 @@ func (f *fmt) fmt_q(s string) {
|
|||||||
if f.sharp && strconv.CanBackquote(s) {
|
if f.sharp && strconv.CanBackquote(s) {
|
||||||
quoted = "`" + s + "`"
|
quoted = "`" + s + "`"
|
||||||
} else {
|
} else {
|
||||||
quoted = strconv.Quote(s)
|
if f.plus {
|
||||||
|
quoted = strconv.QuoteToASCII(s)
|
||||||
|
} else {
|
||||||
|
quoted = strconv.Quote(s)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
f.padString(quoted)
|
f.padString(quoted)
|
||||||
}
|
}
|
||||||
@ -299,7 +324,12 @@ func (f *fmt) fmt_q(s string) {
|
|||||||
// fmt_qc formats the integer as a single-quoted, escaped Go character constant.
|
// fmt_qc formats the integer as a single-quoted, escaped Go character constant.
|
||||||
// If the character is not valid Unicode, it will print '\ufffd'.
|
// If the character is not valid Unicode, it will print '\ufffd'.
|
||||||
func (f *fmt) fmt_qc(c int64) {
|
func (f *fmt) fmt_qc(c int64) {
|
||||||
quoted := strconv.QuoteRune(int(c))
|
var quoted string
|
||||||
|
if f.plus {
|
||||||
|
quoted = strconv.QuoteRuneToASCII(int(c))
|
||||||
|
} else {
|
||||||
|
quoted = strconv.QuoteRune(int(c))
|
||||||
|
}
|
||||||
f.padString(quoted)
|
f.padString(quoted)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,6 +363,8 @@ func (p *pp) fmt0x64(v uint64, leading0x bool) {
|
|||||||
// temporarily turning on the unicode flag and tweaking the precision.
|
// temporarily turning on the unicode flag and tweaking the precision.
|
||||||
func (p *pp) fmtUnicode(v int64) {
|
func (p *pp) fmtUnicode(v int64) {
|
||||||
precPresent := p.fmt.precPresent
|
precPresent := p.fmt.precPresent
|
||||||
|
sharp := p.fmt.sharp
|
||||||
|
p.fmt.sharp = false
|
||||||
prec := p.fmt.prec
|
prec := p.fmt.prec
|
||||||
if !precPresent {
|
if !precPresent {
|
||||||
// If prec is already set, leave it alone; otherwise 4 is minimum.
|
// If prec is already set, leave it alone; otherwise 4 is minimum.
|
||||||
@ -370,10 +372,13 @@ func (p *pp) fmtUnicode(v int64) {
|
|||||||
p.fmt.precPresent = true
|
p.fmt.precPresent = true
|
||||||
}
|
}
|
||||||
p.fmt.unicode = true // turn on U+
|
p.fmt.unicode = true // turn on U+
|
||||||
|
p.fmt.uniQuote = sharp
|
||||||
p.fmt.integer(int64(v), 16, unsigned, udigits)
|
p.fmt.integer(int64(v), 16, unsigned, udigits)
|
||||||
p.fmt.unicode = false
|
p.fmt.unicode = false
|
||||||
|
p.fmt.uniQuote = false
|
||||||
p.fmt.prec = prec
|
p.fmt.prec = prec
|
||||||
p.fmt.precPresent = precPresent
|
p.fmt.precPresent = precPresent
|
||||||
|
p.fmt.sharp = sharp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) {
|
func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) {
|
||||||
|
Loading…
Reference in New Issue
Block a user