Copyright: The Go Authors. All rights reserved.//Use of this source code are governed by a bsd-style//license so can be found in the license file. go/src/fmt/format.go//version 1.7package Fmtimport ("StrConv" "Unicode/utf8")//For conversion to const (Ldigits = " 0123456789abcdefx "udigits =" 0123456789ABCDEFX ")//used as a parameter to facilitate the reader to understand what the incoming parameter means const (signed = Trueunsigned = False)//used to record Whether the corresponding tag is specified in the placeholder//flags are placed in a separate structure to facilitate cleanup of type fmtflags struct {widpresent bool//Width value precpresent bool//precision value minus bool -Mark plus bool//+ Mark sharp BOOL//# Mark space bool//space Mark zero BOOL//0 mark//for special formats%+v and% #v , set the PLUSV/SHARPV flag separately. PLUSV BOOL//+VSHARPV BOOL//#v}//FMT is a primitive formatter used in functions such as Printf. It outputs the formatted result to a buffer, which must be specified separately. Type FMT struct {buf *buffer//*[]bytefmtflags//struct, defines many flags WID int//width PREC int//precision//intbuf enough to store binary format in t64intbuf [68]byte}//Reset All flags func (f *fmt) Clearflags () {f.fmtflags = fmtflags{}}//struct initialization (must provide buffer) func (f *fmt) init (BUF * Buffer{f.buf = Buff.clearflags ()}//writes data to buffer (writes only n bytes of padding character) func (f *fmt) writepadding (n int) {if n <= 0 {return}buf: = *f.buf The capacity is determined first, if the capacity is insufficient, then the expansion oldlen: = Len (buf) Newlen: = Oldlen + nif newlen > Cap (BUF) {//default will double the capacity, but to ensure that the write//content can be accommodated, so +nbuf = make (buffer, Cap (BUF) *2+n) copy (buf, *f.buf)}//determines the character to write padbyte: = Byte (") if F.zero {padbyte = byte (' 0 ')}//start writing Paddin G: = buf[oldlen:newlen]for I: = range padding {padding[i] = padbyte}//buf may have been expanded (address changed), so write back *f.buf = buf[:newlen]}/ /write data to buffer (write byte slice, processing width padding simultaneously) func (f *fmt) pad (b []byte) {///If no width value, write directly if!f.widpresent | | f.wid = 0 {f.buf.write (b) retu The rn}//width value is measured in characters rather than bytes (without regard to the feelings of the Chinese characters). Width: = F.wid-utf8. Runecount (b) If!f.minus {//specified '-' tag, padding on left f.writepadding (width) f.buf.write (b)} else {//unspecified '-' tag, padding f.buf.write on the right side (b) F.writepadding (width)}}//writes data to the buffer (writes a string while processing the width padding) func (f *fmt) padstring (s string) {//If there is no width value, write directly if!f.widpresent | | F.wid = = 0 {f.buf.writestring (s) return}//the width value is in characters as a unit, not as a byte (without regard to the feelings of Chinese characters). Width: = F.wid-utf8. RUnecountinstring (s) if!f.minus {//specified '-' tag, padding on left f.writepadding (width) f.buf.writestring (s)} else {//unspecified '-' tag, fill F on right . buf. WriteString (s) f.writepadding (width)}}//writes data to buffer (Boolean value) func (f *fmt) Fmt_boolean (v bool) {if v {f.padstring ("true")} else {f.padstring ("false")}} Writes data to the buffer (writes Unicode code point)//Unicode code point format "U+FFFF", if the # tag is specified, the format is "U+ffff ' corresponding character '". Func (f *fmt) Fmt_unicode (U UInt64) {//temporary buffer, capacity 68 bytes, can be expanded if the capacity is insufficient. BUF: = f.intbuf[0:]//1, determine whether the capacity is sufficient//if no precision is specified, then the capacity is certainly sufficient, because even if the use of the% #U 1 to format,//the maximum required storage space is only 18 bytes ("U+ffffffffffffffff"), no More than 68. It is possible to exceed the capacity range only after specifying too large a precision, such as 100. So the next face of the capacity of the judgment, and precision is only related. The default precision is 4 (if the code point length is less than 4 bits, add a leading 0, such as u+0065, if the//code point length exceeds the precision value, the precision is ignored) Prec: = 4//If precision is specified, determines whether the formatted result will exceed the BUF range if f.precpresent &A mp;& F.prec > 4 {prec = f.prec//estimates the required storage space: "u+", Precision, "'", corresponding character, "'". Width: = 2 + prec + 2 + UTF8. Utfmax + 1if width > len (buf) {buf = make ([]byte, width)}}//start formatting//right-to-left formatting easier some i: = Len (BUF)//2, Process # Mark//At last add ' phase should be the character '. The premise is that the value must be within the Unicode code point range, and the character can print if F.sharP && u <= UTF8. Maxrune && StrConv. Isprint (Rune (U)) {i--buf[i] = ' \ ' i-= UTF8. Runelen (Rune (U)) utf8. Encoderune (buf[i:], Rune (U)) i--buf[i] = ' \ ' i--buf[i] = '}//3, Format u as a hexadecimal value. For u >= + {i--//OK BUF write subscript buf[i] = udigits[u&0xf]//With 1111 phase, get hexadecimal single digit, then check the table for the character. prec--//accuracy is used for a U >>= 4//drop hexadecimal single digit}i--//processing the last one-digit buf[ I] = udigits[u]prec--//4, processing precision information (add leading 0) for Prec > 0 {i--buf[i] = ' 0 ' prec--}//5, processing leading "u+". I--buf[i] = ' + ' i--buf[i] = ' U '//6, Processing width information (padding space) Oldzero: = F.zerof.zero = Falsef.pad (buf[i:]) F.zero = oldzero}//writes data to buffer (integer Number: Includes signed and unsigned, processing a binary conversion)//u: The integer to be formatted. Base: Binary. IsSigned: whether there are symbols. Digits: Binary conversion table//16 binary case determined by the digits parameter func (f *fmt) Fmt_integer (u uint64, base int, issigned bool, digits string) {//1, fixup parameter Number//If there is a sign, the negative numbers stored in U are changed to positive negative: = issigned && Int64 (U) < 0if negative {u =-u//equals-int64 (U), type conversion does not change value contents , so minus whichever is the same,-U saves one step conversion operation}//temporary buffer, capacity is 68 bytes, if the capacity is not enough, you canTo be expanded. BUF: = f.intbuf[0:]//2, determine if the capacity is sufficient if F.widpresent | | F.precpresent {//requires an additional 3 bytes to hold the signed "0x". In order to improve efficiency, the width and precision are added directly (in fact the width and precision overlap)//Because in most cases, the result of the addition is not too large, the width > len (buf) is very//less, it is seldom re-allocated memory, so this is only to ensure security. Conversely, if the correct width value is calculated using a judgment statement, the efficiency is reduced. Width: = 3 + f.wid + f.precif width > len (buf) {buf = make ([]byte, width)}}//3, determine accuracy information//NOTE: There are two ways to add a leading 0 to an integer:%.3d or%08d,// If both of these are used, the 0 tag is ignored and the width is padded with spaces. The default precision is 0, and if precision is specified, the specified precision is used. Prec: = 0if f.precpresent {prec = f.prec//If the precision is specified as 0 and the value is also specified as 0, then there is no content and only spaces are populated. For example: FMT. Printf ("% #8. D", 0) if Prec = = 0 && U = = 0 {oldzero: = F.zerof.zero = Falsef.writepadding (f.wid) F.zero = Oldzeroretu rn}//If no precision is specified, but 0 marks and widths are specified,//the width value is converted to the precision value, and the leading 0 is handled by the precision processing function. } else if F.zero && f.widpresent {prec = f.wid//if a symbol bit is specified, leave a sign bit if negative | | f.plus | | f.space {prec--}}//from right to It's easier to format the left some I: = Len (BUF)//4, Start coding//using constants for division and modulo operations can be more efficient. The case order is sorted by usage frequency. Switch base {case 10:for u >= {i--//OK buffer write subscript Next: = u/10//Remove single digit//here used-and * for the remainder, and no use%, is not faster than%? Buf[i] = byte (' 0 ' + u-next*10)//Get single digit u = next}case 16:for u >= + {i--//OK buffer write subscript buf[i] = Dig ITS[U&0XF]//with 1111, gets the hexadecimal single digit and then checks the table for the character. U >>= 4//drop hexadecimal single digit}case 8:for u >= 8 {i--//OK buffer write subscript buf[i] = byte (' 0 ' + U&7)//With 111, gets the single digit of octal and then converts to characters. U >>= 3//Discard octal single digit}case 2:for u >= 2 {i--//OK buffer write subscript buf[i] = byte (' 0 ' + u&1)//vs. 1, gets the single digit of the binary, and then converts to characters. U >>= 1//Drop binary single digit}default:panic ("Fmt:unknown base; Can ' t happen ")//Unknown carry system}i--//The last single digit has not been processed, here processing buf[i] = Digits[u]//All the decimal digits of the binary can look up the table to take the character. 5, processing precision information (add leading 0) for i > 0 && prec > Len (buf)-i {i--buf[i] = ' 0 '}//6, processing prefix: 0x, 0, etc. if f.sharp {switch base { Case 8:if buf[i]! = ' 0 ' {i--buf[i] = ' 0 '}case 16://based on the parameter digits to determine the capitalization: 0x, 0xi--buf[i] = digits[16]i--buf[i] = ' 0 '}}//7, Handler Number bit if negative {i--Buf[i] = '-'} else if f.plus {i--buf[i] = ' + '} else if f.space {i--buf[i] = '}//8, processing width information (padding spaces) Oldzero: = F.zerof.zero = Falsef.pad (buf[i:]) F.zero = oldzero}//truncates the string to the specified precision func (f *fmt) truncate (s string) string {if f.precpresent {n: = F.PRECF or I: = range S {n--if N < 0 {return S[:i]}}}return s}//writes data to buffer (string: processing width and precision information) func (f *fmt) fmt_s (s string) {s = f.tr Uncate (s) f.padstring (s)}//writes data to buffer (string/byte slice: hexadecimal format) func (f *fmt) FMT_SBX (s string, b []byte, digits string) {//1, calculated result length Gets the string or byte slice length to be processed long: = Len (b) if b = = Nil {length = Len (s)}//only handles content within the accuracy range if f.precpresent && F.prec < Leng th {length = f.prec}//each element (bytes) requires 2 bytes to store its hexadecimal encoding. Width: = 2 * Lengthif width > 0 {if f.space {//elements have spaces between them, so you need to add 0x or 0X before each element. The hexadecimal encoding of each element is exactly 2 bytes, so multiply by 2,//Just 2 bytes more space per element to hold 0x or 0Xif f.sharp {width *= 2}//each element will be separated by a space width + = length- 1} else if F.sharp {//elements have no spaces between them, simply add a 0x or 0X at the beginning. width + = 2}} else {//element is empty, only spaces are filled with widths, for example: FMT. Printf ("%8x", "") if F.widpresent {F.WRItepadding (F.wid)}return}//2, processing "left" width information if f.widpresent && f.wid > Width &&!f.minus {f.writepadding ( F.wid-width)}//3, start encoding buf: = *f.buf//Add a leading 0x or 0X before the first element. If F.sharp {buf = append (buf, ' 0 ', digits[16])}//traverse individual elements (bytes) var c bytefor I: = 0; i < length; Add spaces between i++ {//elements, preceded by 0x or 0X for each element. If F.space && i > 0 {buf = append (buf, ") if F.sharp {buf = append (buf, ' 0 ', digits[16])}}//encode the current element if b! = Nil {c = B[i]} else {c = s[i]}buf = Append (buf, digits[c>>4], digits[c&0xf])}//because of append operation, the buffer may be extended *f.buf = b uf//4, handle "right" width information if f.widpresent && f.wid > Width && f.minus {f.writepadding (f.wid-width)}}//write data to buffer (string: Hex format) func (f *fmt) fmt_sx (s, digits string) {F.FMT_SBX (s, nil, digits)}//writes data to buffer (byte slice: hexadecimal format) func (f *fmt) fmt_bx (b []byte, digits string) {F.FMT_SBX ("", b, digits)}//writes data to buffer (string: With double quotes, not escaped)//If a # tag is specified and the string does not contain any control characters (except tab),//Returns an original string (with an inverted quotation mark). Func (f *fmt) Fmt_q (s string) {///1, processing precision information//truncates string to specified precision s = F.truncaTE (s)//2, start encode//Process # if F.sharp && StrConv. Canbackquote (s) {f.padstring ("'" + S + "'") return}//temporary buffer, storing temporary encoding result buf: = f.intbuf[:0]//encoding and processing width information if F.plus {//non-ASCII characters will be converted to Unicode code point F.pad (StrConv. Appendquotetoascii (buf, s))} else {//non-ASCII characters will output normally f.pad (StrConv. Appendquote (buf, s))}}//writes data to buffer (character)//If the character is not a valid Unicode encoding, write ' \ufffd ' func (f *fmt) Fmt_c (c UInt64) {r: = Rune (c)//exceeds Unicode range if C > UTF8. Maxrune {r = UTF8. runeerror}//temporary buffer buf: = f.intbuf[:0]//encode r w: = UTF8. Encoderune (Buf[:utf8. Utfmax], R)//writes the encoded result to the buffer F.pad (Buf[:w])}//writes the data to the buffer (character: with single quotation marks, not escaped)//writes ' \UFFFD ' func (f *fmt) If the character is not a valid Unicode encoding FMT_QC (c UInt64) {r: = Rune (c)//exceeds the Unicode range if C > UTF8. Maxrune {r = UTF8. runeerror}//temporary buffer buf: = f.intbuf[:0]//encode and process width information if F.plus {//non-ASCII characters will be converted to Unicode code point F.pad (StrConv. Appendquoterunetoascii (BUF, R))} else {//non-ASCII characters will be output f.pad normally (StrConv. Appendquoterune (BUF, R))}}//writes data to buffer (float64)//If the verb provided by the argument is a valid format delimiter, it can be in StrConv. Appendfloat in//converts it to a byte type incoming.Func (f *fmt) fmt_float (v float64, size int, verb rune, Prec int) {///1, Start encoding//"placeholder" in precision overrides the default precision in the parameter if F.precpresent {PREC = f.prec}//formatted numeric value, the result is written to a temporary buffer, and a space is reserved for the + number num: = StrConv. Appendfloat (F.intbuf[:1], V, byte (verb), prec, size)//2, processing symbol//If the conversion result is signed, remove the reserved space, otherwise the reserved space will be converted to + if num[1] = = '-' | | NUM[1] = = ' + ' {num = num[1:]} else {num[0] = ' + '}//if a space tag is specified and the + tag is not specified, the + is changed to a space. If F.space && num[0] = = ' + ' &&!f.plus {num[0] = '}//3, handling infinity and non-numbers//It does not look like a number, so it should not be filled with 0. If num[1] = = ' I ' | | NUM[1] = = ' N ' {oldzero: = F.zerof.zero = false//If no symbol is specified, remove the preceding symbol if num[1] = = ' N ' &&!f.space &&!f. Plus {num = num[1:]}f.pad (num) F.zero = oldzeroreturn}//4, after processing the fill write f.buf//specified + number | | The + sign is not specified and the result is not preceded by +. If F.plus | | NUM[0]! = ' + ' {//if left padding with 0, then we want the symbol to be in front of all 0. If F.zero && f.widpresent && f.wid > Len (num) {f.buf.writebyte (num[0])//write symbol f.writepadding (f . Wid-len (num))//Fill F.buf.write (num[1:])//write to the content other than the symbol Return}f.pad (NUM) return}//does not specify a + number, but the result is the + sign minus the + number. F.pad (num[1:])}
Standard library-fmt/format.go interpretation