├── LICENSE ├── README.md ├── README_cn.md ├── align.go ├── align_test.go ├── builder.go ├── bytes_viewer.go ├── bytes_viewer_test.go ├── cmd ├── jsonfmt │ └── main.go └── tablefmt │ └── main.go ├── examples └── main.go ├── flatten.go ├── flatten_test.go ├── fmt.go ├── fmt_row_test.go ├── fmt_test.go ├── format.go ├── format_test.go ├── go.mod ├── misc.go ├── opt.go ├── puts.go ├── sort.go ├── stack.go ├── stack_test.go ├── table.go └── table_test.go /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016-NOW wzshiming 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Golang beautify data display for Humans 2 | 3 | [![Go Report Card](https://goreportcard.com/badge/github.com/go-ffmt/ffmt)](https://goreportcard.com/report/github.com/go-ffmt/ffmt) 4 | [![GoDoc](https://pkg.go.dev/badge/github.com/gopkg.in/ffmt.v1)](https://pkg.go.dev/gopkg.in/ffmt.v1) 5 | [![GitHub license](https://img.shields.io/github/license/go-ffmt/ffmt.svg)](https://github.com/go-ffmt/ffmt/blob/master/LICENSE) 6 | [![gocover.io](https://gocover.io/_badge/github.com/go-ffmt/ffmt)](https://gocover.io/github.com/go-ffmt/ffmt) 7 | 8 | - [English](https://github.com/go-ffmt/ffmt/blob/master/README.md) 9 | - [简体中文](https://github.com/go-ffmt/ffmt/blob/master/README_cn.md) 10 | 11 | ## Usage 12 | 13 | [Examples](https://github.com/go-ffmt/ffmt/blob/master/examples/main.go) 14 | 15 | ``` golang 16 | package main 17 | 18 | import ( 19 | ffmt "gopkg.in/ffmt.v1" 20 | ) 21 | 22 | func main() { 23 | example() 24 | } 25 | 26 | type mt struct { 27 | String string 28 | Int int 29 | Slice []int 30 | Map map[string]interface{} 31 | } 32 | 33 | func example() { 34 | m := mt{ 35 | "hello world", 36 | 100, 37 | []int{1, 2, 3, 4, 5, 6}, 38 | map[string]interface{}{ 39 | "A": 123, 40 | "BB": 456, 41 | }, 42 | } 43 | 44 | fmt.Println(m) // fmt the default formatting. 45 | /* 46 | {hello world 100 [1 2 3 4 5 6] map[BB:456 A:123]} 47 | */ 48 | 49 | ffmt.Puts(m) // More friendly formatting. 50 | /* 51 | { 52 | String: "hello world" 53 | Int: 100 54 | Slice: [ 55 | 1 2 3 56 | 4 5 6 57 | ] 58 | Map: { 59 | "A": 123 60 | "BB": 456 61 | } 62 | } 63 | */ 64 | 65 | ffmt.Print(m) // Same "Puts" but String unadded '"'. 66 | /* 67 | { 68 | String: hello world 69 | Int: 100 70 | Slice: [ 71 | 1 2 3 72 | 4 5 6 73 | ] 74 | Map: { 75 | A: 123 76 | BB: 456 77 | } 78 | } 79 | */ 80 | 81 | ffmt.P(m) // Format data and types. 82 | /* 83 | main.mt{ 84 | String: string("hello world") 85 | Int: int(100) 86 | Slice: []int[ 87 | int(1) int(2) int(3) 88 | int(4) int(5) int(6) 89 | ] 90 | Map: map[string]interface {}{ 91 | string("A"): int(123) 92 | string("BB"): int(456) 93 | } 94 | } 95 | */ 96 | 97 | ffmt.Pjson(m) // Format it in json style. 98 | /* 99 | { 100 | "Int": 100 101 | ,"Map": { 102 | "A": 123 103 | ,"BB": 456 104 | } 105 | ,"Slice": [ 106 | 1,2,3 107 | ,4,5,6 108 | ] 109 | ,"String": "hello world" 110 | } 111 | */ 112 | 113 | m0 := ffmt.ToTable(m, m) // Break the fields into tables. 114 | ffmt.Puts(m0) 115 | /* 116 | [ 117 | [ 118 | "String" "Int" 119 | "Slice" "Map" 120 | ] 121 | [ 122 | "hello world" "100" 123 | "[1 2 3 4 5 6]" "map[A:123 BB:456]" 124 | ] 125 | ] 126 | */ 127 | 128 | m1 := ffmt.FmtTable(m0) // [][]string Table format. 129 | ffmt.Puts(m1) 130 | /* 131 | [ 132 | "String Int Slice Map " 133 | "hello world 100 [1 2 3 4 5 6] map[A:123 BB:456] " 134 | ] 135 | */ 136 | 137 | ffmt.Mark("hello") // Mark position. 138 | /* 139 | main.go:124 hello 140 | */ 141 | 142 | ffmt.Print(ffmt.BytesViewer("Hello world! Hello All!")) 143 | /* 144 | | Address | Hex | Text | 145 | | -------: | :---------------------------------------------- | :--------------- | 146 | | 00000000 | 48 65 6c 6c 6f 20 77 6f 72 6c 64 21 20 48 65 6c | Hello world! Hel | 147 | | 00000010 | 6c 6f 20 41 6c 6c 21 | lo All! | 148 | */ 149 | } 150 | 151 | ``` 152 | 153 | ## Sponsors 154 | 155 | [![jetbrains](https://www.jetbrains.com/shop/static/images/jetbrains-logo-inv.svg)](https://www.jetbrains.com/shop/eform/opensource) 156 | 157 | ## License 158 | 159 | Licensed under the MIT License. See [LICENSE](https://github.com/go-ffmt/ffmt/blob/master/LICENSE) for the full license text. 160 | -------------------------------------------------------------------------------- /README_cn.md: -------------------------------------------------------------------------------- 1 | # golang 美化数据展示 2 | 3 | [![Go Report Card](https://goreportcard.com/badge/github.com/go-ffmt/ffmt)](https://goreportcard.com/report/github.com/go-ffmt/ffmt) 4 | [![GoDoc](https://pkg.go.dev/badge/github.com/gopkg.in/ffmt.v1)](https://pkg.go.dev/gopkg.in/ffmt.v1) 5 | [![GitHub license](https://img.shields.io/github/license/go-ffmt/ffmt.svg)](https://github.com/go-ffmt/ffmt/blob/master/LICENSE) 6 | [![gocover.io](https://gocover.io/_badge/github.com/go-ffmt/ffmt)](https://gocover.io/github.com/go-ffmt/ffmt) 7 | 8 | - [English](https://github.com/go-ffmt/ffmt/blob/master/README.md) 9 | - [简体中文](https://github.com/go-ffmt/ffmt/blob/master/README_cn.md) 10 | 11 | ## 用法 12 | 13 | [示例](https://github.com/go-ffmt/ffmt/blob/master/examples/main.go) 14 | 15 | ``` golang 16 | package main 17 | 18 | import ( 19 | ffmt "gopkg.in/ffmt.v1" 20 | ) 21 | 22 | func main() { 23 | example() 24 | } 25 | 26 | type mt struct { 27 | String string 28 | Int int 29 | Slice []int 30 | Map map[string]interface{} 31 | } 32 | 33 | func example() { 34 | m := mt{ 35 | "hello world", 36 | 100, 37 | []int{1, 2, 3, 4, 5, 6}, 38 | map[string]interface{}{ 39 | "A": 123, 40 | "BB": 456, 41 | }, 42 | } 43 | 44 | fmt.Println(m) // fmt 默认输出 45 | /* 46 | {hello world 100 [1 2 3 4 5 6] map[BB:456 A:123]} 47 | */ 48 | 49 | ffmt.Puts(m) // 较为友好的输出 50 | /* 51 | { 52 | String: "hello world" 53 | Int: 100 54 | Slice: [ 55 | 1 2 3 56 | 4 5 6 57 | ] 58 | Map: { 59 | "A": 123 60 | "BB": 456 61 | } 62 | } 63 | */ 64 | 65 | ffmt.Print(m) // 同 Puts 但是字符串不加引号 66 | /* 67 | { 68 | String: hello world 69 | Int: 100 70 | Slice: [ 71 | 1 2 3 72 | 4 5 6 73 | ] 74 | Map: { 75 | A: 123 76 | BB: 456 77 | } 78 | } 79 | */ 80 | 81 | ffmt.P(m) // 友好格式化加上类型 82 | /* 83 | main.mt{ 84 | String: string("hello world") 85 | Int: int(100) 86 | Slice: []int[ 87 | int(1) int(2) int(3) 88 | int(4) int(5) int(6) 89 | ] 90 | Map: map[string]interface {}{ 91 | string("A"): int(123) 92 | string("BB"): int(456) 93 | } 94 | } 95 | */ 96 | 97 | ffmt.Pjson(m) // 以 json 风格输出 98 | /* 99 | { 100 | "Int": 100 101 | ,"Map": { 102 | "A": 123 103 | ,"BB": 456 104 | } 105 | ,"Slice": [ 106 | 1,2,3 107 | ,4,5,6 108 | ] 109 | ,"String": "hello world" 110 | } 111 | */ 112 | 113 | m0 := ffmt.ToTable(m, m) // 按字段拆成表 114 | ffmt.Puts(m0) 115 | /* 116 | [ 117 | [ 118 | "String" "Int" 119 | "Slice" "Map" 120 | ] 121 | [ 122 | "hello world" "100" 123 | "[1 2 3 4 5 6]" "map[A:123 BB:456]" 124 | ] 125 | ] 126 | */ 127 | 128 | m1 := ffmt.FmtTable(m0) // [][]string 表格式化 129 | ffmt.Puts(m1) 130 | /* 131 | [ 132 | "String Int Slice Map " 133 | "hello world 100 [1 2 3 4 5 6] map[A:123 BB:456] " 134 | ] 135 | */ 136 | 137 | ffmt.Mark("hello") // 标记输出位置 138 | /* 139 | main.go:124 hello 140 | */ 141 | 142 | ffmt.Print(ffmt.BytesViewer("Hello world! Hello All!")) 143 | /* 144 | | Address | Hex | Text | 145 | | -------: | :---------------------------------------------- | :--------------- | 146 | | 00000000 | 48 65 6c 6c 6f 20 77 6f 72 6c 64 21 20 48 65 6c | Hello world! Hel | 147 | | 00000010 | 6c 6f 20 41 6c 6c 21 | lo All! | 148 | */ 149 | } 150 | ``` 151 | 152 | ## 赞助 153 | 154 | [![jetbrains](https://www.jetbrains.com/shop/static/images/jetbrains-logo-inv.svg)](https://www.jetbrains.com/shop/eform/opensource) 155 | 156 | ## 许可证 157 | 158 | 软包根据MIT License。有关完整的许可证文本,请参阅[LICENSE](https://github.com/go-ffmt/ffmt/blob/master/LICENSE)。 159 | -------------------------------------------------------------------------------- /align.go: -------------------------------------------------------------------------------- 1 | package ffmt 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | // align 8 | type align struct { 9 | child *align 10 | next *align 11 | value builder 12 | colon int // This is the data separated by a colon. The position of the colon is used to align the data after the colon. 13 | } 14 | 15 | // lrPos Indented empty brackets 16 | func (n *align) lrPos() { 17 | b := n 18 | for x := b; x != nil && x.next != nil; x = x.next { 19 | if x.child != nil { 20 | continue 21 | } 22 | ss := x.next.value.String() 23 | if len(ss) == 2 && (ss[1] == ')' || ss[1] == ']' || ss[1] == '}') { 24 | x.mergeNext(1) 25 | } 26 | } 27 | } 28 | 29 | // tablePos Aligning array type data 30 | func (n *align) tablePos() { 31 | ms := []int{} 32 | b := n 33 | max := 0 34 | for x := b; x != nil; x = x.next { 35 | if x.colon > 0 || x.child != nil { 36 | return 37 | } 38 | ll := strLen(x.value.String()) 39 | ms = append(ms, ll) 40 | if ll > max { 41 | max = ll 42 | } 43 | } 44 | 45 | if max < 10 { 46 | n.merge(9, ms) 47 | } else if max < 18 { 48 | n.merge(5, ms) 49 | } else if max < 30 { 50 | n.merge(3, ms) 51 | } 52 | } 53 | 54 | // merge Merge to the next node 55 | func (n *align) merge(m int, ms []int) { 56 | l := len(ms) 57 | col := 0 58 | for i := 0; i != m; i++ { 59 | z := m - i 60 | if l > z && l%z == 0 { 61 | col = z 62 | break 63 | } 64 | } 65 | if col > 1 { 66 | n.mergeNextSize(col, ms) 67 | } 68 | } 69 | 70 | // mergeNextSize Merge to the next node specified length 71 | func (n *align) mergeNextSize(s int, ms []int) { 72 | lmax := make([]int, s) 73 | for j := 0; j != s; j++ { 74 | for i := 0; i*s < len(ms); i++ { 75 | b := i*s + j 76 | if ms[b] > lmax[j] { 77 | lmax[j] = ms[b] 78 | } 79 | } 80 | } 81 | for i := 1; i < len(lmax); i++ { 82 | lmax[i] += lmax[i-1] 83 | } 84 | for x := n; x != nil; x = x.next { 85 | for i := 0; i < s-1 && x.next != nil; i++ { 86 | x.mergeNext(lmax[i]) 87 | } 88 | } 89 | } 90 | 91 | // spac 92 | func (n *align) spac(i int) { 93 | for k := 0; k < i; k++ { 94 | n.value.WriteByte(Space) 95 | } 96 | } 97 | 98 | // mergeNext Merge the next node to the current node 99 | func (n *align) mergeNext(max int) { 100 | n.spac(max - strLen(n.value.String())) 101 | n.value.WriteString(n.next.value.String()) 102 | putBuilder(n.next.value) 103 | n.next = n.next.next 104 | } 105 | 106 | // Align the data after the colon 107 | func (n *align) colonPos() { 108 | b := n 109 | for b != nil { 110 | m := 0 111 | for x := b; x != nil; x = x.next { 112 | if x.colon <= 0 { 113 | continue 114 | } 115 | bl := strLen(x.value.String()[:x.colon]) 116 | if bl > m { 117 | m = bl 118 | } 119 | if x.child != nil { 120 | break 121 | } 122 | } 123 | for x := b; x != nil; x = x.next { 124 | 125 | if x.colon > 0 { 126 | bl := strLen(x.value.String()[:x.colon]) 127 | if m-bl > 0 { 128 | t := strings.Replace(x.value.String(), colSym, colSym+spac(m-bl), 1) 129 | x.value.Reset() 130 | x.value.WriteString(t) 131 | } 132 | } 133 | b = x.next 134 | if x.child != nil { 135 | break 136 | } 137 | } 138 | } 139 | } 140 | 141 | func (n *align) put() { 142 | if n.value != nil { 143 | putBuilder(n.value) 144 | n.value = nil 145 | } 146 | if n.child != nil { 147 | n.child.put() 148 | } 149 | if n.next != nil { 150 | n.next.put() 151 | } 152 | } 153 | 154 | func (n *align) String() string { 155 | buf := getBuilder() 156 | defer putBuilder(buf) 157 | n.strings(0, buf) 158 | s := buf.String() 159 | if len(s) >= 2 { 160 | return s[2:] 161 | } 162 | return "" 163 | } 164 | 165 | func (n *align) strings(d int, buf builder) { 166 | buf.WriteString(spacing(d)) 167 | buf.WriteString(n.value.String()) 168 | if n.child != nil { 169 | n.child.strings(d+1, buf) 170 | } 171 | if x := n.next; x != nil { 172 | x.strings(d, buf) 173 | } 174 | } 175 | 176 | func (n *align) toChild() (e *align) { 177 | if n.child == nil { 178 | buf := getBuilder() 179 | n.child = &align{ 180 | value: buf, 181 | } 182 | } 183 | return n.child 184 | } 185 | 186 | func (n *align) toNext() (e *align) { 187 | if n.next == nil { 188 | buf := getBuilder() 189 | n.next = &align{ 190 | value: buf, 191 | } 192 | } 193 | return n.next 194 | } 195 | 196 | func getDepth(a string) int { 197 | for i := 0; i != len(a); i++ { 198 | switch a[i] { 199 | case Space: 200 | case ',': 201 | return i + 1 202 | default: 203 | return i 204 | } 205 | } 206 | return 0 207 | } 208 | 209 | func stringToNode(a string) *align { 210 | ss := strings.Split(a, "\n") 211 | depth := 0 212 | o := &align{} 213 | x := o 214 | buf := getBuilder() 215 | x.value = buf 216 | st := []*align{} 217 | for i := 0; i != len(ss); i++ { 218 | b := ss[i] 219 | d := getDepth(b) 220 | switch { 221 | case d == depth: 222 | x = x.toNext() 223 | case d > depth: 224 | st = append(st, x) 225 | x = x.toChild() 226 | case d < depth: 227 | if len(st) == 0 { 228 | x = x.toNext() 229 | } else { 230 | x = st[len(st)-1] 231 | if x != nil { 232 | st = st[:len(st)-1] 233 | x.child.colonPos() 234 | x.child.tablePos() 235 | x.child.lrPos() 236 | x = x.toNext() 237 | } 238 | } 239 | } 240 | 241 | depth = d 242 | if d > 0 { 243 | d-- 244 | } 245 | x.value.WriteString(b[d:]) 246 | x.colon = strings.Index(x.value.String(), colSym) 247 | } 248 | return o 249 | } 250 | 251 | // Align returns align structured strings 252 | func Align(a string) string { 253 | s := stringToNode(a) 254 | defer s.put() 255 | return s.String() 256 | } 257 | -------------------------------------------------------------------------------- /align_test.go: -------------------------------------------------------------------------------- 1 | package ffmt 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | ) 7 | 8 | func TestAlign(t *testing.T) { 9 | b := ` 10 | { 11 | key: value 12 | slice: [ 13 | hello 14 | world 15 | 1 16 | 2 17 | ] 18 | } 19 | ` 20 | 21 | out := ` 22 | { 23 | key: value 24 | slice: [ 25 | hello world 26 | 1 2 27 | ] 28 | } 29 | ` 30 | if strings.TrimSpace(Align(b)) != strings.TrimSpace(out) { 31 | t.Fail() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /builder.go: -------------------------------------------------------------------------------- 1 | package ffmt 2 | 3 | import ( 4 | "bytes" 5 | "sync" 6 | ) 7 | 8 | type builder interface { 9 | String() string 10 | Write([]byte) (int, error) // io.Writer 11 | WriteString(string) (int, error) // io.WriteString 12 | WriteByte(byte) error // io.ByteWriter 13 | Reset() 14 | Len() int 15 | } 16 | 17 | var poolBuilder = sync.Pool{ 18 | New: newBuilder, 19 | } 20 | 21 | func getBuilder() builder { 22 | buf := poolBuilder.Get().(builder) 23 | return buf 24 | } 25 | 26 | func putBuilder(buf builder) { 27 | buf.Reset() 28 | poolBuilder.Put(buf) 29 | } 30 | 31 | func newBuilder() interface{} { 32 | const malloc = 1024 33 | return bytes.NewBuffer(make([]byte, 0, malloc)) 34 | } 35 | -------------------------------------------------------------------------------- /bytes_viewer.go: -------------------------------------------------------------------------------- 1 | package ffmt 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "strconv" 7 | "unicode" 8 | "unsafe" 9 | ) 10 | 11 | // BytesViewer bytes viewer 12 | type BytesViewer []byte 13 | 14 | // String returns view in hexadecimal 15 | func (b BytesViewer) String() string { 16 | if len(b) == 0 { 17 | return invalid 18 | } 19 | const head = ` 20 | | Address | Hex | Text | 21 | | -------: | :---------------------------------------------- | :--------------- | 22 | ` 23 | const row = 16 24 | result := make([]byte, 0, len(head)/2*(len(b)/16+3)) 25 | result = append(result, head...) 26 | for i := 0; i < len(b); i += row { 27 | result = append(result, "| "...) 28 | result = append(result, fmt.Sprintf("%08x", i)...) 29 | result = append(result, " | "...) 30 | 31 | k := i + row 32 | more := 0 33 | if k >= len(b) { 34 | more = k - len(b) 35 | k = len(b) 36 | } 37 | for j := i; j != k; j++ { 38 | if b[j] < 16 { 39 | result = append(result, '0') 40 | } 41 | result = strconv.AppendUint(result, uint64(b[j]), 16) 42 | result = append(result, ' ') 43 | } 44 | for j := 0; j != more; j++ { 45 | result = append(result, " "...) 46 | } 47 | result = append(result, "| "...) 48 | buf := bytes.Map(func(r rune) rune { 49 | if unicode.IsSpace(r) { 50 | return ' ' 51 | } 52 | return r 53 | }, b[i:k]) 54 | result = append(result, buf...) 55 | for j := 0; j != more; j++ { 56 | result = append(result, ' ') 57 | } 58 | result = append(result, " |\n"...) 59 | } 60 | return *(*string)(unsafe.Pointer(&result)) 61 | } 62 | -------------------------------------------------------------------------------- /bytes_viewer_test.go: -------------------------------------------------------------------------------- 1 | package ffmt 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | ) 7 | 8 | func TestBytesViewer(t *testing.T) { 9 | tests := []struct { 10 | b BytesViewer 11 | want string 12 | }{ 13 | {BytesViewer("Hello world!"), `| Address | Hex | Text | 14 | | -------: | :---------------------------------------------- | :--------------- | 15 | | 00000000 | 48 65 6c 6c 6f 20 77 6f 72 6c 64 21 | Hello world! |`}, 16 | } 17 | for _, tt := range tests { 18 | if got := tt.b.String(); strings.TrimSpace(got) != strings.TrimSpace(tt.want) { 19 | t.Fail() 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /cmd/jsonfmt/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "flag" 6 | "fmt" 7 | "io/ioutil" 8 | "os" 9 | 10 | "gopkg.in/ffmt.v1" 11 | ) 12 | 13 | var ( 14 | w = flag.Bool("w", false, "Write the changes to the file") 15 | ) 16 | 17 | func init() { 18 | flag.Usage = func() { 19 | w := os.Stdout 20 | fmt.Fprintf(w, "jsonfmt:\n") 21 | fmt.Fprintf(w, "Usage:\n") 22 | fmt.Fprintf(w, " %s [Options] file1 [filen ...]\n", os.Args[0]) 23 | fmt.Fprintf(w, "Options:\n") 24 | flag.PrintDefaults() 25 | } 26 | flag.Parse() 27 | } 28 | 29 | func main() { 30 | args := flag.Args() 31 | if len(args) == 0 { 32 | flag.Usage() 33 | return 34 | } 35 | for _, file := range args { 36 | err := format(file, *w) 37 | if err != nil { 38 | fmt.Println(err) 39 | flag.Usage() 40 | return 41 | } 42 | } 43 | } 44 | 45 | func format(file string, w bool) error { 46 | b, err := ioutil.ReadFile(file) 47 | if err != nil { 48 | return err 49 | } 50 | var i interface{} 51 | err = json.Unmarshal(b, &i) 52 | if err != nil { 53 | return err 54 | } 55 | ret := ffmt.Spjson(i) 56 | if !w { 57 | fmt.Print(ret) 58 | return nil 59 | } 60 | 61 | err = ioutil.WriteFile(file, []byte(ret), 0666) 62 | if err != nil { 63 | return err 64 | } 65 | return nil 66 | } 67 | -------------------------------------------------------------------------------- /cmd/tablefmt/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "io/ioutil" 7 | "os" 8 | 9 | ffmt "gopkg.in/ffmt.v1" 10 | ) 11 | 12 | var ( 13 | w = flag.Bool("w", false, "Write the changes to the file") 14 | prefix = flag.String("p", "//", "Prefix") 15 | split = flag.String("s", ",", "Split rune") 16 | ) 17 | 18 | func init() { 19 | flag.Usage = func() { 20 | w := os.Stdout 21 | fmt.Fprintf(w, "tablefmt:\n") 22 | fmt.Fprintf(w, "Usage:\n") 23 | fmt.Fprintf(w, " %s [Options] file1 [filen ...]\n", os.Args[0]) 24 | fmt.Fprintf(w, "Options:\n") 25 | flag.PrintDefaults() 26 | } 27 | flag.Parse() 28 | } 29 | 30 | func main() { 31 | args := flag.Args() 32 | if len(args) == 0 { 33 | flag.Usage() 34 | return 35 | } 36 | for _, file := range args { 37 | err := format(file, *prefix, *split, *w) 38 | if err != nil { 39 | fmt.Println(err) 40 | flag.Usage() 41 | return 42 | } 43 | } 44 | } 45 | 46 | func format(file string, prefix, split string, w bool) error { 47 | b, err := ioutil.ReadFile(file) 48 | if err != nil { 49 | return err 50 | } 51 | 52 | ret := ffmt.TableText(string(b), prefix, split) 53 | if !w { 54 | fmt.Print(ret) 55 | return nil 56 | } 57 | 58 | err = ioutil.WriteFile(file, []byte(ret), 0666) 59 | if err != nil { 60 | return err 61 | } 62 | return nil 63 | } 64 | -------------------------------------------------------------------------------- /examples/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | ffmt "gopkg.in/ffmt.v1" 7 | ) 8 | 9 | func main() { 10 | example() 11 | } 12 | 13 | type mt struct { 14 | String string 15 | Int int 16 | Slice []int 17 | Map map[string]interface{} 18 | } 19 | 20 | func example() { 21 | m := mt{ 22 | "hello world", 23 | 100, 24 | []int{1, 2, 3, 4, 5, 6}, 25 | map[string]interface{}{ 26 | "A": 123, 27 | "BB": 456, 28 | }, 29 | } 30 | 31 | fmt.Println(m) // fmt 默认输出 32 | /* 33 | {hello world 100 [1 2 3 4 5 6] map[BB:456 A:123]} 34 | */ 35 | 36 | ffmt.Puts(m) // 较为友好的输出 37 | /* 38 | { 39 | String: "hello world" 40 | Int: 100 41 | Slice: [ 42 | 1 2 3 43 | 4 5 6 44 | ] 45 | Map: { 46 | "A": 123 47 | "BB": 456 48 | } 49 | } 50 | */ 51 | 52 | ffmt.Print(m) // 同 Puts 但是字符串不加引号 53 | /* 54 | { 55 | String: hello world 56 | Int: 100 57 | Slice: [ 58 | 1 2 3 59 | 4 5 6 60 | ] 61 | Map: { 62 | A: 123 63 | BB: 456 64 | } 65 | } 66 | */ 67 | 68 | ffmt.P(m) // 友好格式化加上类型 69 | /* 70 | main.mt{ 71 | String: string("hello world") 72 | Int: int(100) 73 | Slice: []int[ 74 | int(1) int(2) int(3) 75 | int(4) int(5) int(6) 76 | ] 77 | Map: map[string]interface {}{ 78 | string("A"): int(123) 79 | string("BB"): int(456) 80 | } 81 | } 82 | */ 83 | 84 | ffmt.Pjson(m) // 以 json 风格输出 85 | /* 86 | { 87 | "Int": 100 88 | ,"Map": { 89 | "A": 123 90 | ,"BB": 456 91 | } 92 | ,"Slice": [ 93 | 1,2,3 94 | ,4,5,6 95 | ] 96 | ,"String": "hello world" 97 | } 98 | */ 99 | 100 | m0 := ffmt.ToTable(m, m) // 按字段拆成表 101 | ffmt.Puts(m0) 102 | /* 103 | [ 104 | [ 105 | "String" "Int" 106 | "Slice" "Map" 107 | ] 108 | [ 109 | "hello world" "100" 110 | "[1 2 3 4 5 6]" "map[A:123 BB:456]" 111 | ] 112 | ] 113 | */ 114 | 115 | m1 := ffmt.FmtTable(m0) // [][]string 表格式化 116 | ffmt.Puts(m1) 117 | /* 118 | [ 119 | "String Int Slice Map " 120 | "hello world 100 [1 2 3 4 5 6] map[A:123 BB:456] " 121 | ] 122 | */ 123 | 124 | ffmt.Mark("hello") // 标记输出位置 125 | /* 126 | main.go:124 hello 127 | */ 128 | 129 | ffmt.Print(ffmt.BytesViewer("Hello world! Hello All!")) 130 | /* 131 | | Address | Hex | Text | 132 | | -------: | :---------------------------------------------- | :--------------- | 133 | | 00000000 | 48 65 6c 6c 6f 20 77 6f 72 6c 64 21 20 48 65 6c | Hello world! Hel | 134 | | 00000010 | 6c 6f 20 41 6c 6c 21 | lo All! | 135 | */ 136 | } 137 | -------------------------------------------------------------------------------- /flatten.go: -------------------------------------------------------------------------------- 1 | package ffmt 2 | 3 | import ( 4 | "strconv" 5 | "strings" 6 | ) 7 | 8 | func Flatten(nested map[string]interface{}) map[string]interface{} { 9 | if nested == nil { 10 | return nested 11 | } 12 | flatmap := map[string]interface{}{} 13 | var prefixes []string 14 | flatten(0, flatmap, nested, prefixes) 15 | return flatmap 16 | } 17 | 18 | func flatten(deep int, flatMap map[string]interface{}, nested interface{}, prefixes []string) { 19 | switch t := nested.(type) { 20 | case map[string]interface{}: 21 | for k, v := range t { 22 | flatten(deep+1, flatMap, v, append(prefixes, k)) 23 | } 24 | case []interface{}: 25 | for i, v := range t { 26 | flatten(deep+1, flatMap, v, append(prefixes, strconv.Itoa(i))) 27 | } 28 | default: 29 | key := strings.Join(prefixes, ".") 30 | flatMap[key] = t 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /flatten_test.go: -------------------------------------------------------------------------------- 1 | package ffmt 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func TestFlatten(t *testing.T) { 9 | type args struct { 10 | nested map[string]interface{} 11 | } 12 | tests := []struct { 13 | name string 14 | args args 15 | want map[string]interface{} 16 | }{ 17 | { 18 | args: args{ 19 | nested: map[string]interface{}{}, 20 | }, 21 | want: map[string]interface{}{}, 22 | }, 23 | { 24 | args: args{ 25 | nested: map[string]interface{}{ 26 | "a": 1, 27 | }, 28 | }, 29 | want: map[string]interface{}{ 30 | "a": 1, 31 | }, 32 | }, 33 | { 34 | args: args{ 35 | nested: map[string]interface{}{ 36 | "a": 1, 37 | "bb": map[string]interface{}{ 38 | "ccc": 2, 39 | }, 40 | }, 41 | }, 42 | want: map[string]interface{}{ 43 | "a": 1, 44 | "bb.ccc": 2, 45 | }, 46 | }, 47 | { 48 | args: args{ 49 | nested: map[string]interface{}{ 50 | "a": 1, 51 | "bb": []interface{}{ 52 | "cc", 2, 53 | }, 54 | }, 55 | }, 56 | want: map[string]interface{}{ 57 | "a": 1, 58 | "bb.0": "cc", 59 | "bb.1": 2, 60 | }, 61 | }, 62 | { 63 | args: args{ 64 | nested: map[string]interface{}{ 65 | "a": 1, 66 | "bb": []interface{}{ 67 | map[string]interface{}{ 68 | "ddd": 3, 69 | }, "cc", 70 | }, 71 | }, 72 | }, 73 | want: map[string]interface{}{ 74 | "a": 1, 75 | "bb.1": "cc", 76 | "bb.0.ddd": 3, 77 | }, 78 | }, 79 | } 80 | for _, tt := range tests { 81 | t.Run(tt.name, func(t *testing.T) { 82 | if got := Flatten(tt.args.nested); !reflect.DeepEqual(got, tt.want) { 83 | t.Errorf("Flatten() = %v, want %v", got, tt.want) 84 | } 85 | }) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /fmt.go: -------------------------------------------------------------------------------- 1 | package ffmt 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "reflect" 7 | "strconv" 8 | "unicode" 9 | "unicode/utf8" 10 | ) 11 | 12 | const ( 13 | invalidJSON = "null" 14 | invalid = "" 15 | private = "" 16 | ) 17 | 18 | type format struct { 19 | optional 20 | buf builder 21 | filter map[uintptr]bool 22 | } 23 | 24 | func (s *format) write(b []byte) { 25 | s.buf.Write(b) 26 | } 27 | 28 | func (s *format) writeByte(b byte) { 29 | s.buf.WriteByte(b) 30 | } 31 | 32 | func (s *format) writeString(str string) { 33 | s.buf.WriteString(str) 34 | } 35 | 36 | func (s *format) writeFormat(format string, a ...interface{}) { 37 | fmt.Fprintf(s.buf, format, a...) 38 | } 39 | 40 | func (s *format) fmt(va reflect.Value, depth int) { 41 | if !va.IsValid() { 42 | s.nilBuf() 43 | return 44 | } 45 | 46 | if va.Kind() == reflect.Ptr && va.IsNil() { 47 | s.nilBuf() 48 | return 49 | } 50 | 51 | v := va 52 | if depth >= s.depth { 53 | s.defaultBuf(v) 54 | return 55 | } 56 | 57 | if s.getString(v) { 58 | return 59 | } 60 | 61 | for v.Kind() == reflect.Ptr { 62 | if s.opt.IsCanDefaultString() { 63 | if s.filter[v.Pointer()] { 64 | s.xxBuf(v, v.Pointer()) 65 | return 66 | } 67 | s.filter[v.Pointer()] = true 68 | } 69 | 70 | v = v.Elem() 71 | if !v.IsValid() { 72 | s.nilBuf() 73 | return 74 | } 75 | switch s.style { 76 | case StylePjson: 77 | default: 78 | s.writeByte('&') 79 | } 80 | if s.getString(va) { 81 | return 82 | } 83 | } 84 | s.switchType(v, depth) 85 | } 86 | 87 | func (s *format) switchType(v reflect.Value, depth int) { 88 | switch v.Kind() { 89 | case reflect.Invalid: 90 | s.nilBuf() 91 | case reflect.Struct: 92 | switch s.style { 93 | case StylePjson: 94 | s.mapBuf(reflect.ValueOf(struct2Map(v)), depth) 95 | default: 96 | s.structBuf(v, depth) 97 | } 98 | case reflect.Map: 99 | s.mapBuf(v, depth) 100 | case reflect.Array, reflect.Slice: 101 | s.sliceBuf(v, depth) 102 | case reflect.String: 103 | s.stringBuf(v) 104 | case reflect.Func: 105 | s.funcBuf(v) 106 | case reflect.Uintptr: 107 | s.xxBuf(v, v.Uint()) 108 | case reflect.Chan, reflect.Ptr, reflect.UnsafePointer: 109 | s.xxBuf(v, v.Pointer()) 110 | case reflect.Interface: 111 | v = v.Elem() 112 | if v.IsValid() { 113 | s.fmt(v, depth) 114 | } else { 115 | s.nilBuf() 116 | } 117 | default: 118 | s.defaultBuf(v) 119 | } 120 | } 121 | 122 | // depthBuf write buffer with depth 123 | func (s *format) depthBuf(i int) { 124 | s.writeByte('\n') 125 | for k := 0; k < i; k++ { 126 | s.writeByte(Space) 127 | } 128 | } 129 | 130 | // nilBuf write buffer with nil 131 | func (s *format) nilBuf() { 132 | switch s.style { 133 | case StylePjson: 134 | s.writeString(invalidJSON) 135 | default: 136 | s.writeString(invalid) 137 | } 138 | } 139 | 140 | // defaultBuf write buffer with default string 141 | func (s *format) defaultBuf(v reflect.Value) { 142 | s.nameBuf(v.Type()) 143 | switch s.style { 144 | case StyleP: 145 | s.writeByte('(') 146 | s.writeFormat("%#v", v.Interface()) 147 | s.writeByte(')') 148 | case StylePjson: 149 | d, _ := json.Marshal(v.Interface()) 150 | s.write(d) 151 | default: 152 | s.writeFormat("%+v", v.Interface()) 153 | } 154 | return 155 | } 156 | 157 | // stringBuf write buffer with string 158 | func (s *format) stringBuf(v reflect.Value) { 159 | switch s.style { 160 | case StyleP: 161 | s.defaultBuf(v) 162 | case StylePuts, StylePjson: 163 | s.writeString(strconv.Quote(v.String())) 164 | default: 165 | s.writeString(v.String()) 166 | } 167 | return 168 | } 169 | 170 | // funcBuf write buffer with func address 171 | func (s *format) funcBuf(v reflect.Value) { 172 | switch s.style { 173 | case StylePjson: 174 | s.writeByte('"') 175 | defer s.writeByte('"') 176 | case StyleP: 177 | s.writeByte('<') 178 | defer s.writeByte('>') 179 | } 180 | s.writeString("func(") 181 | t := v.Type() 182 | if t.NumIn() != 0 { 183 | for i := 0; ; { 184 | s.writeString(t.In(i).String()) 185 | i++ 186 | if i == t.NumIn() { 187 | break 188 | } 189 | s.writeByte(',') 190 | } 191 | } 192 | s.writeString(")(") 193 | if t.NumOut() != 0 { 194 | for i := 0; ; { 195 | s.writeString(t.Out(i).String()) 196 | i++ 197 | if i == t.NumOut() { 198 | break 199 | } 200 | s.writeByte(',') 201 | } 202 | } 203 | s.writeByte(')') 204 | s.writeFormat("(0x%020x)", v.Pointer()) 205 | return 206 | } 207 | 208 | // xxBuf write buffer with hex format 209 | func (s *format) xxBuf(v reflect.Value, i interface{}) { 210 | switch s.style { 211 | case StylePjson: 212 | s.writeByte('"') 213 | defer s.writeByte('"') 214 | case StyleP: 215 | s.writeByte('<') 216 | defer s.writeByte('>') 217 | } 218 | s.nameBuf(v.Type()) 219 | s.writeFormat("(0x%020x)", i) 220 | return 221 | } 222 | 223 | // structBuf write buffer with struct 224 | func (s *format) structBuf(v reflect.Value, depth int) { 225 | s.nameBuf(v.Type()) 226 | s.writeByte('{') 227 | t := v.Type() 228 | for i := 0; i != t.NumField(); i++ { 229 | f := t.Field(i) 230 | v0 := v.Field(i) 231 | s.depthBuf(depth + 1) 232 | s.writeString(f.Name) 233 | s.writeString(colSym) 234 | if isPrivateName(f.Name) { 235 | s.writeString(private) 236 | } else { 237 | s.fmt(v0, depth+1) 238 | } 239 | } 240 | s.depthBuf(depth) 241 | s.writeByte('}') 242 | return 243 | } 244 | 245 | // mapBuf write buffer with map 246 | func (s *format) mapBuf(v reflect.Value, depth int) { 247 | mk := v.MapKeys() 248 | valueSlice(mk).Sort() 249 | s.nameBuf(v.Type()) 250 | s.writeByte('{') 251 | for i := 0; i != len(mk); i++ { 252 | k := mk[i] 253 | switch s.style { 254 | case StylePjson: 255 | if i != 0 { 256 | s.depthBuf(depth) 257 | s.writeByte(',') 258 | } else { 259 | s.depthBuf(depth + 1) 260 | } 261 | default: 262 | s.depthBuf(depth + 1) 263 | } 264 | s.fmt(k, s.depth-1) 265 | s.writeString(colSym) 266 | s.fmt(v.MapIndex(k), depth+1) 267 | } 268 | s.depthBuf(depth) 269 | s.writeByte('}') 270 | return 271 | } 272 | 273 | // sliceBuf write buffer with slice 274 | func (s *format) sliceBuf(v reflect.Value, depth int) { 275 | s.nameBuf(v.Type()) 276 | s.writeByte('[') 277 | for i := 0; i != v.Len(); i++ { 278 | switch s.style { 279 | case StylePjson: 280 | if i != 0 { 281 | s.depthBuf(depth) 282 | s.writeByte(',') 283 | } else { 284 | s.depthBuf(depth + 1) 285 | } 286 | default: 287 | s.depthBuf(depth + 1) 288 | } 289 | s.fmt(v.Index(i), depth+1) 290 | } 291 | s.depthBuf(depth) 292 | s.writeByte(']') 293 | return 294 | } 295 | 296 | // nameBuf write buffer with type name 297 | func (s *format) nameBuf(t reflect.Type) bool { 298 | switch s.style { 299 | case StyleP: 300 | switch t.Kind() { 301 | case reflect.Map: 302 | s.writeString("map[") 303 | s.nameBuf(t.Key()) 304 | s.writeByte(']') 305 | return s.nameBuf(t.Elem()) 306 | case reflect.Slice: 307 | s.writeString("[]") 308 | return s.nameBuf(t.Elem()) 309 | case reflect.Array: 310 | s.writeByte('[') 311 | s.writeString(strconv.FormatInt(int64(t.Len()), 10)) 312 | s.writeByte(']') 313 | return s.nameBuf(t.Elem()) 314 | case reflect.Ptr: 315 | s.writeByte('*') 316 | return s.nameBuf(t.Elem()) 317 | default: 318 | if pkg := t.PkgPath(); pkg != "" { 319 | s.writeString(pkg) 320 | s.writeByte('.') 321 | } 322 | 323 | if t.Name() != "" { 324 | s.writeString(t.Name()) 325 | } else { 326 | s.writeString(t.String()) 327 | } 328 | return true 329 | } 330 | } 331 | return false 332 | } 333 | 334 | // getString write buffer with default string 335 | // returns true if can't default string 336 | func (s *format) getString(v reflect.Value) bool { 337 | if !s.opt.IsCanDefaultString() { 338 | return false 339 | } 340 | 341 | switch s.style { 342 | case StylePjson: 343 | r := getString(v) 344 | if r == "" { 345 | return false 346 | } 347 | vv, _ := json.Marshal(v.Interface()) 348 | s.write(vv) 349 | case StyleP: 350 | r := getString(v) 351 | if r == "" { 352 | return false 353 | } 354 | s.writeByte('<') 355 | s.writeString(r) 356 | s.writeByte('>') 357 | default: 358 | r := getString(v) 359 | if r == "" { 360 | return false 361 | } 362 | s.writeString(r) 363 | } 364 | return true 365 | } 366 | 367 | // getString return default string 368 | func getString(v reflect.Value) string { 369 | 370 | if v.Kind() == reflect.Interface { 371 | if v.IsNil() { 372 | return "" 373 | } 374 | return getString(v.Elem()) 375 | } 376 | 377 | if !v.CanInterface() { 378 | return "" 379 | } 380 | 381 | i := v.Interface() 382 | 383 | if e, b := i.(fmt.Stringer); b && e != nil { 384 | return e.String() 385 | } 386 | if e, b := i.(fmt.GoStringer); b && e != nil { 387 | return e.GoString() 388 | } 389 | return "" 390 | } 391 | 392 | // isPrivateName returns it is a private name 393 | func isPrivateName(name string) bool { 394 | ch, _ := utf8.DecodeRuneInString(name) 395 | return !unicode.IsUpper(ch) 396 | } 397 | 398 | // struct2Map returns map from struct 399 | func struct2Map(v reflect.Value) map[string]interface{} { 400 | t := v.Type() 401 | data := map[string]interface{}{} 402 | for i := 0; i < t.NumField(); i++ { 403 | f := t.Field(i) 404 | if isPrivateName(f.Name) { 405 | continue 406 | } 407 | data[f.Name] = v.Field(i).Interface() 408 | } 409 | return data 410 | } 411 | -------------------------------------------------------------------------------- /fmt_row_test.go: -------------------------------------------------------------------------------- 1 | package ffmt 2 | 3 | import ( 4 | "bytes" 5 | "strings" 6 | "testing" 7 | ) 8 | 9 | func newRowTestData(l int) [][]int { 10 | rowtestdata := make([][]int, 0, l) 11 | for i := 0; i != l; i++ { 12 | rowtestdata = append(rowtestdata, make([]int, i)) 13 | } 14 | return rowtestdata 15 | } 16 | 17 | func TestRowPrint(t *testing.T) { 18 | buf := bytes.NewBuffer(nil) 19 | rowtestdata := newRowTestData(100) 20 | for _, v := range rowtestdata { 21 | Fprint(buf, v) 22 | } 23 | 24 | if strings.TrimSpace(buf.String()) != strings.TrimSpace(rowtestdataout) { 25 | t.Fail() 26 | } 27 | } 28 | 29 | var rowtestdataout = ` 30 | [ 31 | ] 32 | [ 33 | 0 34 | ] 35 | [ 36 | 0 37 | 0 38 | ] 39 | [ 40 | 0 41 | 0 42 | 0 43 | ] 44 | [ 45 | 0 0 46 | 0 0 47 | ] 48 | [ 49 | 0 50 | 0 51 | 0 52 | 0 53 | 0 54 | ] 55 | [ 56 | 0 0 0 57 | 0 0 0 58 | ] 59 | [ 60 | 0 61 | 0 62 | 0 63 | 0 64 | 0 65 | 0 66 | 0 67 | ] 68 | [ 69 | 0 0 0 0 70 | 0 0 0 0 71 | ] 72 | [ 73 | 0 0 0 74 | 0 0 0 75 | 0 0 0 76 | ] 77 | [ 78 | 0 0 0 0 0 79 | 0 0 0 0 0 80 | ] 81 | [ 82 | 0 83 | 0 84 | 0 85 | 0 86 | 0 87 | 0 88 | 0 89 | 0 90 | 0 91 | 0 92 | 0 93 | ] 94 | [ 95 | 0 0 0 0 0 0 96 | 0 0 0 0 0 0 97 | ] 98 | [ 99 | 0 100 | 0 101 | 0 102 | 0 103 | 0 104 | 0 105 | 0 106 | 0 107 | 0 108 | 0 109 | 0 110 | 0 111 | 0 112 | ] 113 | [ 114 | 0 0 0 0 0 0 0 115 | 0 0 0 0 0 0 0 116 | ] 117 | [ 118 | 0 0 0 0 0 119 | 0 0 0 0 0 120 | 0 0 0 0 0 121 | ] 122 | [ 123 | 0 0 0 0 0 0 0 0 124 | 0 0 0 0 0 0 0 0 125 | ] 126 | [ 127 | 0 128 | 0 129 | 0 130 | 0 131 | 0 132 | 0 133 | 0 134 | 0 135 | 0 136 | 0 137 | 0 138 | 0 139 | 0 140 | 0 141 | 0 142 | 0 143 | 0 144 | ] 145 | [ 146 | 0 0 0 0 0 0 0 0 0 147 | 0 0 0 0 0 0 0 0 0 148 | ] 149 | [ 150 | 0 151 | 0 152 | 0 153 | 0 154 | 0 155 | 0 156 | 0 157 | 0 158 | 0 159 | 0 160 | 0 161 | 0 162 | 0 163 | 0 164 | 0 165 | 0 166 | 0 167 | 0 168 | 0 169 | ] 170 | [ 171 | 0 0 0 0 0 172 | 0 0 0 0 0 173 | 0 0 0 0 0 174 | 0 0 0 0 0 175 | ] 176 | [ 177 | 0 0 0 0 0 0 0 178 | 0 0 0 0 0 0 0 179 | 0 0 0 0 0 0 0 180 | ] 181 | [ 182 | 0 0 183 | 0 0 184 | 0 0 185 | 0 0 186 | 0 0 187 | 0 0 188 | 0 0 189 | 0 0 190 | 0 0 191 | 0 0 192 | 0 0 193 | ] 194 | [ 195 | 0 196 | 0 197 | 0 198 | 0 199 | 0 200 | 0 201 | 0 202 | 0 203 | 0 204 | 0 205 | 0 206 | 0 207 | 0 208 | 0 209 | 0 210 | 0 211 | 0 212 | 0 213 | 0 214 | 0 215 | 0 216 | 0 217 | 0 218 | ] 219 | [ 220 | 0 0 0 0 0 0 0 0 221 | 0 0 0 0 0 0 0 0 222 | 0 0 0 0 0 0 0 0 223 | ] 224 | [ 225 | 0 0 0 0 0 226 | 0 0 0 0 0 227 | 0 0 0 0 0 228 | 0 0 0 0 0 229 | 0 0 0 0 0 230 | ] 231 | [ 232 | 0 0 233 | 0 0 234 | 0 0 235 | 0 0 236 | 0 0 237 | 0 0 238 | 0 0 239 | 0 0 240 | 0 0 241 | 0 0 242 | 0 0 243 | 0 0 244 | 0 0 245 | ] 246 | [ 247 | 0 0 0 0 0 0 0 0 0 248 | 0 0 0 0 0 0 0 0 0 249 | 0 0 0 0 0 0 0 0 0 250 | ] 251 | [ 252 | 0 0 0 0 0 0 0 253 | 0 0 0 0 0 0 0 254 | 0 0 0 0 0 0 0 255 | 0 0 0 0 0 0 0 256 | ] 257 | [ 258 | 0 259 | 0 260 | 0 261 | 0 262 | 0 263 | 0 264 | 0 265 | 0 266 | 0 267 | 0 268 | 0 269 | 0 270 | 0 271 | 0 272 | 0 273 | 0 274 | 0 275 | 0 276 | 0 277 | 0 278 | 0 279 | 0 280 | 0 281 | 0 282 | 0 283 | 0 284 | 0 285 | 0 286 | 0 287 | ] 288 | [ 289 | 0 0 0 0 0 0 290 | 0 0 0 0 0 0 291 | 0 0 0 0 0 0 292 | 0 0 0 0 0 0 293 | 0 0 0 0 0 0 294 | ] 295 | [ 296 | 0 297 | 0 298 | 0 299 | 0 300 | 0 301 | 0 302 | 0 303 | 0 304 | 0 305 | 0 306 | 0 307 | 0 308 | 0 309 | 0 310 | 0 311 | 0 312 | 0 313 | 0 314 | 0 315 | 0 316 | 0 317 | 0 318 | 0 319 | 0 320 | 0 321 | 0 322 | 0 323 | 0 324 | 0 325 | 0 326 | 0 327 | ] 328 | [ 329 | 0 0 0 0 0 0 0 0 330 | 0 0 0 0 0 0 0 0 331 | 0 0 0 0 0 0 0 0 332 | 0 0 0 0 0 0 0 0 333 | ] 334 | [ 335 | 0 0 0 336 | 0 0 0 337 | 0 0 0 338 | 0 0 0 339 | 0 0 0 340 | 0 0 0 341 | 0 0 0 342 | 0 0 0 343 | 0 0 0 344 | 0 0 0 345 | 0 0 0 346 | ] 347 | [ 348 | 0 0 349 | 0 0 350 | 0 0 351 | 0 0 352 | 0 0 353 | 0 0 354 | 0 0 355 | 0 0 356 | 0 0 357 | 0 0 358 | 0 0 359 | 0 0 360 | 0 0 361 | 0 0 362 | 0 0 363 | 0 0 364 | 0 0 365 | ] 366 | [ 367 | 0 0 0 0 0 0 0 368 | 0 0 0 0 0 0 0 369 | 0 0 0 0 0 0 0 370 | 0 0 0 0 0 0 0 371 | 0 0 0 0 0 0 0 372 | ] 373 | [ 374 | 0 0 0 0 0 0 0 0 0 375 | 0 0 0 0 0 0 0 0 0 376 | 0 0 0 0 0 0 0 0 0 377 | 0 0 0 0 0 0 0 0 0 378 | ] 379 | [ 380 | 0 381 | 0 382 | 0 383 | 0 384 | 0 385 | 0 386 | 0 387 | 0 388 | 0 389 | 0 390 | 0 391 | 0 392 | 0 393 | 0 394 | 0 395 | 0 396 | 0 397 | 0 398 | 0 399 | 0 400 | 0 401 | 0 402 | 0 403 | 0 404 | 0 405 | 0 406 | 0 407 | 0 408 | 0 409 | 0 410 | 0 411 | 0 412 | 0 413 | 0 414 | 0 415 | 0 416 | 0 417 | ] 418 | [ 419 | 0 0 420 | 0 0 421 | 0 0 422 | 0 0 423 | 0 0 424 | 0 0 425 | 0 0 426 | 0 0 427 | 0 0 428 | 0 0 429 | 0 0 430 | 0 0 431 | 0 0 432 | 0 0 433 | 0 0 434 | 0 0 435 | 0 0 436 | 0 0 437 | 0 0 438 | ] 439 | [ 440 | 0 0 0 441 | 0 0 0 442 | 0 0 0 443 | 0 0 0 444 | 0 0 0 445 | 0 0 0 446 | 0 0 0 447 | 0 0 0 448 | 0 0 0 449 | 0 0 0 450 | 0 0 0 451 | 0 0 0 452 | 0 0 0 453 | ] 454 | [ 455 | 0 0 0 0 0 0 0 0 456 | 0 0 0 0 0 0 0 0 457 | 0 0 0 0 0 0 0 0 458 | 0 0 0 0 0 0 0 0 459 | 0 0 0 0 0 0 0 0 460 | ] 461 | [ 462 | 0 463 | 0 464 | 0 465 | 0 466 | 0 467 | 0 468 | 0 469 | 0 470 | 0 471 | 0 472 | 0 473 | 0 474 | 0 475 | 0 476 | 0 477 | 0 478 | 0 479 | 0 480 | 0 481 | 0 482 | 0 483 | 0 484 | 0 485 | 0 486 | 0 487 | 0 488 | 0 489 | 0 490 | 0 491 | 0 492 | 0 493 | 0 494 | 0 495 | 0 496 | 0 497 | 0 498 | 0 499 | 0 500 | 0 501 | 0 502 | 0 503 | ] 504 | [ 505 | 0 0 0 0 0 0 0 506 | 0 0 0 0 0 0 0 507 | 0 0 0 0 0 0 0 508 | 0 0 0 0 0 0 0 509 | 0 0 0 0 0 0 0 510 | 0 0 0 0 0 0 0 511 | ] 512 | [ 513 | 0 514 | 0 515 | 0 516 | 0 517 | 0 518 | 0 519 | 0 520 | 0 521 | 0 522 | 0 523 | 0 524 | 0 525 | 0 526 | 0 527 | 0 528 | 0 529 | 0 530 | 0 531 | 0 532 | 0 533 | 0 534 | 0 535 | 0 536 | 0 537 | 0 538 | 0 539 | 0 540 | 0 541 | 0 542 | 0 543 | 0 544 | 0 545 | 0 546 | 0 547 | 0 548 | 0 549 | 0 550 | 0 551 | 0 552 | 0 553 | 0 554 | 0 555 | 0 556 | ] 557 | [ 558 | 0 0 0 0 559 | 0 0 0 0 560 | 0 0 0 0 561 | 0 0 0 0 562 | 0 0 0 0 563 | 0 0 0 0 564 | 0 0 0 0 565 | 0 0 0 0 566 | 0 0 0 0 567 | 0 0 0 0 568 | 0 0 0 0 569 | ] 570 | [ 571 | 0 0 0 0 0 0 0 0 0 572 | 0 0 0 0 0 0 0 0 0 573 | 0 0 0 0 0 0 0 0 0 574 | 0 0 0 0 0 0 0 0 0 575 | 0 0 0 0 0 0 0 0 0 576 | ] 577 | [ 578 | 0 0 579 | 0 0 580 | 0 0 581 | 0 0 582 | 0 0 583 | 0 0 584 | 0 0 585 | 0 0 586 | 0 0 587 | 0 0 588 | 0 0 589 | 0 0 590 | 0 0 591 | 0 0 592 | 0 0 593 | 0 0 594 | 0 0 595 | 0 0 596 | 0 0 597 | 0 0 598 | 0 0 599 | 0 0 600 | 0 0 601 | ] 602 | [ 603 | 0 604 | 0 605 | 0 606 | 0 607 | 0 608 | 0 609 | 0 610 | 0 611 | 0 612 | 0 613 | 0 614 | 0 615 | 0 616 | 0 617 | 0 618 | 0 619 | 0 620 | 0 621 | 0 622 | 0 623 | 0 624 | 0 625 | 0 626 | 0 627 | 0 628 | 0 629 | 0 630 | 0 631 | 0 632 | 0 633 | 0 634 | 0 635 | 0 636 | 0 637 | 0 638 | 0 639 | 0 640 | 0 641 | 0 642 | 0 643 | 0 644 | 0 645 | 0 646 | 0 647 | 0 648 | 0 649 | 0 650 | ] 651 | [ 652 | 0 0 0 0 0 0 0 0 653 | 0 0 0 0 0 0 0 0 654 | 0 0 0 0 0 0 0 0 655 | 0 0 0 0 0 0 0 0 656 | 0 0 0 0 0 0 0 0 657 | 0 0 0 0 0 0 0 0 658 | ] 659 | [ 660 | 0 0 0 0 0 0 0 661 | 0 0 0 0 0 0 0 662 | 0 0 0 0 0 0 0 663 | 0 0 0 0 0 0 0 664 | 0 0 0 0 0 0 0 665 | 0 0 0 0 0 0 0 666 | 0 0 0 0 0 0 0 667 | ] 668 | [ 669 | 0 0 0 0 0 670 | 0 0 0 0 0 671 | 0 0 0 0 0 672 | 0 0 0 0 0 673 | 0 0 0 0 0 674 | 0 0 0 0 0 675 | 0 0 0 0 0 676 | 0 0 0 0 0 677 | 0 0 0 0 0 678 | 0 0 0 0 0 679 | ] 680 | [ 681 | 0 0 0 682 | 0 0 0 683 | 0 0 0 684 | 0 0 0 685 | 0 0 0 686 | 0 0 0 687 | 0 0 0 688 | 0 0 0 689 | 0 0 0 690 | 0 0 0 691 | 0 0 0 692 | 0 0 0 693 | 0 0 0 694 | 0 0 0 695 | 0 0 0 696 | 0 0 0 697 | 0 0 0 698 | ] 699 | [ 700 | 0 0 0 0 701 | 0 0 0 0 702 | 0 0 0 0 703 | 0 0 0 0 704 | 0 0 0 0 705 | 0 0 0 0 706 | 0 0 0 0 707 | 0 0 0 0 708 | 0 0 0 0 709 | 0 0 0 0 710 | 0 0 0 0 711 | 0 0 0 0 712 | 0 0 0 0 713 | ] 714 | [ 715 | 0 716 | 0 717 | 0 718 | 0 719 | 0 720 | 0 721 | 0 722 | 0 723 | 0 724 | 0 725 | 0 726 | 0 727 | 0 728 | 0 729 | 0 730 | 0 731 | 0 732 | 0 733 | 0 734 | 0 735 | 0 736 | 0 737 | 0 738 | 0 739 | 0 740 | 0 741 | 0 742 | 0 743 | 0 744 | 0 745 | 0 746 | 0 747 | 0 748 | 0 749 | 0 750 | 0 751 | 0 752 | 0 753 | 0 754 | 0 755 | 0 756 | 0 757 | 0 758 | 0 759 | 0 760 | 0 761 | 0 762 | 0 763 | 0 764 | 0 765 | 0 766 | 0 767 | 0 768 | ] 769 | [ 770 | 0 0 0 0 0 0 0 0 0 771 | 0 0 0 0 0 0 0 0 0 772 | 0 0 0 0 0 0 0 0 0 773 | 0 0 0 0 0 0 0 0 0 774 | 0 0 0 0 0 0 0 0 0 775 | 0 0 0 0 0 0 0 0 0 776 | ] 777 | [ 778 | 0 0 0 0 0 779 | 0 0 0 0 0 780 | 0 0 0 0 0 781 | 0 0 0 0 0 782 | 0 0 0 0 0 783 | 0 0 0 0 0 784 | 0 0 0 0 0 785 | 0 0 0 0 0 786 | 0 0 0 0 0 787 | 0 0 0 0 0 788 | 0 0 0 0 0 789 | ] 790 | [ 791 | 0 0 0 0 0 0 0 0 792 | 0 0 0 0 0 0 0 0 793 | 0 0 0 0 0 0 0 0 794 | 0 0 0 0 0 0 0 0 795 | 0 0 0 0 0 0 0 0 796 | 0 0 0 0 0 0 0 0 797 | 0 0 0 0 0 0 0 0 798 | ] 799 | [ 800 | 0 0 0 801 | 0 0 0 802 | 0 0 0 803 | 0 0 0 804 | 0 0 0 805 | 0 0 0 806 | 0 0 0 807 | 0 0 0 808 | 0 0 0 809 | 0 0 0 810 | 0 0 0 811 | 0 0 0 812 | 0 0 0 813 | 0 0 0 814 | 0 0 0 815 | 0 0 0 816 | 0 0 0 817 | 0 0 0 818 | 0 0 0 819 | ] 820 | [ 821 | 0 0 822 | 0 0 823 | 0 0 824 | 0 0 825 | 0 0 826 | 0 0 827 | 0 0 828 | 0 0 829 | 0 0 830 | 0 0 831 | 0 0 832 | 0 0 833 | 0 0 834 | 0 0 835 | 0 0 836 | 0 0 837 | 0 0 838 | 0 0 839 | 0 0 840 | 0 0 841 | 0 0 842 | 0 0 843 | 0 0 844 | 0 0 845 | 0 0 846 | 0 0 847 | 0 0 848 | 0 0 849 | 0 0 850 | ] 851 | [ 852 | 0 853 | 0 854 | 0 855 | 0 856 | 0 857 | 0 858 | 0 859 | 0 860 | 0 861 | 0 862 | 0 863 | 0 864 | 0 865 | 0 866 | 0 867 | 0 868 | 0 869 | 0 870 | 0 871 | 0 872 | 0 873 | 0 874 | 0 875 | 0 876 | 0 877 | 0 878 | 0 879 | 0 880 | 0 881 | 0 882 | 0 883 | 0 884 | 0 885 | 0 886 | 0 887 | 0 888 | 0 889 | 0 890 | 0 891 | 0 892 | 0 893 | 0 894 | 0 895 | 0 896 | 0 897 | 0 898 | 0 899 | 0 900 | 0 901 | 0 902 | 0 903 | 0 904 | 0 905 | 0 906 | 0 907 | 0 908 | 0 909 | 0 910 | 0 911 | ] 912 | [ 913 | 0 0 0 0 0 0 914 | 0 0 0 0 0 0 915 | 0 0 0 0 0 0 916 | 0 0 0 0 0 0 917 | 0 0 0 0 0 0 918 | 0 0 0 0 0 0 919 | 0 0 0 0 0 0 920 | 0 0 0 0 0 0 921 | 0 0 0 0 0 0 922 | 0 0 0 0 0 0 923 | ] 924 | [ 925 | 0 926 | 0 927 | 0 928 | 0 929 | 0 930 | 0 931 | 0 932 | 0 933 | 0 934 | 0 935 | 0 936 | 0 937 | 0 938 | 0 939 | 0 940 | 0 941 | 0 942 | 0 943 | 0 944 | 0 945 | 0 946 | 0 947 | 0 948 | 0 949 | 0 950 | 0 951 | 0 952 | 0 953 | 0 954 | 0 955 | 0 956 | 0 957 | 0 958 | 0 959 | 0 960 | 0 961 | 0 962 | 0 963 | 0 964 | 0 965 | 0 966 | 0 967 | 0 968 | 0 969 | 0 970 | 0 971 | 0 972 | 0 973 | 0 974 | 0 975 | 0 976 | 0 977 | 0 978 | 0 979 | 0 980 | 0 981 | 0 982 | 0 983 | 0 984 | 0 985 | 0 986 | ] 987 | [ 988 | 0 0 989 | 0 0 990 | 0 0 991 | 0 0 992 | 0 0 993 | 0 0 994 | 0 0 995 | 0 0 996 | 0 0 997 | 0 0 998 | 0 0 999 | 0 0 1000 | 0 0 1001 | 0 0 1002 | 0 0 1003 | 0 0 1004 | 0 0 1005 | 0 0 1006 | 0 0 1007 | 0 0 1008 | 0 0 1009 | 0 0 1010 | 0 0 1011 | 0 0 1012 | 0 0 1013 | 0 0 1014 | 0 0 1015 | 0 0 1016 | 0 0 1017 | 0 0 1018 | 0 0 1019 | ] 1020 | [ 1021 | 0 0 0 0 0 0 0 0 0 1022 | 0 0 0 0 0 0 0 0 0 1023 | 0 0 0 0 0 0 0 0 0 1024 | 0 0 0 0 0 0 0 0 0 1025 | 0 0 0 0 0 0 0 0 0 1026 | 0 0 0 0 0 0 0 0 0 1027 | 0 0 0 0 0 0 0 0 0 1028 | ] 1029 | [ 1030 | 0 0 0 0 0 0 0 0 1031 | 0 0 0 0 0 0 0 0 1032 | 0 0 0 0 0 0 0 0 1033 | 0 0 0 0 0 0 0 0 1034 | 0 0 0 0 0 0 0 0 1035 | 0 0 0 0 0 0 0 0 1036 | 0 0 0 0 0 0 0 0 1037 | 0 0 0 0 0 0 0 0 1038 | ] 1039 | [ 1040 | 0 0 0 0 0 1041 | 0 0 0 0 0 1042 | 0 0 0 0 0 1043 | 0 0 0 0 0 1044 | 0 0 0 0 0 1045 | 0 0 0 0 0 1046 | 0 0 0 0 0 1047 | 0 0 0 0 0 1048 | 0 0 0 0 0 1049 | 0 0 0 0 0 1050 | 0 0 0 0 0 1051 | 0 0 0 0 0 1052 | 0 0 0 0 0 1053 | ] 1054 | [ 1055 | 0 0 0 0 0 0 1056 | 0 0 0 0 0 0 1057 | 0 0 0 0 0 0 1058 | 0 0 0 0 0 0 1059 | 0 0 0 0 0 0 1060 | 0 0 0 0 0 0 1061 | 0 0 0 0 0 0 1062 | 0 0 0 0 0 0 1063 | 0 0 0 0 0 0 1064 | 0 0 0 0 0 0 1065 | 0 0 0 0 0 0 1066 | ] 1067 | [ 1068 | 0 1069 | 0 1070 | 0 1071 | 0 1072 | 0 1073 | 0 1074 | 0 1075 | 0 1076 | 0 1077 | 0 1078 | 0 1079 | 0 1080 | 0 1081 | 0 1082 | 0 1083 | 0 1084 | 0 1085 | 0 1086 | 0 1087 | 0 1088 | 0 1089 | 0 1090 | 0 1091 | 0 1092 | 0 1093 | 0 1094 | 0 1095 | 0 1096 | 0 1097 | 0 1098 | 0 1099 | 0 1100 | 0 1101 | 0 1102 | 0 1103 | 0 1104 | 0 1105 | 0 1106 | 0 1107 | 0 1108 | 0 1109 | 0 1110 | 0 1111 | 0 1112 | 0 1113 | 0 1114 | 0 1115 | 0 1116 | 0 1117 | 0 1118 | 0 1119 | 0 1120 | 0 1121 | 0 1122 | 0 1123 | 0 1124 | 0 1125 | 0 1126 | 0 1127 | 0 1128 | 0 1129 | 0 1130 | 0 1131 | 0 1132 | 0 1133 | 0 1134 | 0 1135 | ] 1136 | [ 1137 | 0 0 0 0 1138 | 0 0 0 0 1139 | 0 0 0 0 1140 | 0 0 0 0 1141 | 0 0 0 0 1142 | 0 0 0 0 1143 | 0 0 0 0 1144 | 0 0 0 0 1145 | 0 0 0 0 1146 | 0 0 0 0 1147 | 0 0 0 0 1148 | 0 0 0 0 1149 | 0 0 0 0 1150 | 0 0 0 0 1151 | 0 0 0 0 1152 | 0 0 0 0 1153 | 0 0 0 0 1154 | ] 1155 | [ 1156 | 0 0 0 1157 | 0 0 0 1158 | 0 0 0 1159 | 0 0 0 1160 | 0 0 0 1161 | 0 0 0 1162 | 0 0 0 1163 | 0 0 0 1164 | 0 0 0 1165 | 0 0 0 1166 | 0 0 0 1167 | 0 0 0 1168 | 0 0 0 1169 | 0 0 0 1170 | 0 0 0 1171 | 0 0 0 1172 | 0 0 0 1173 | 0 0 0 1174 | 0 0 0 1175 | 0 0 0 1176 | 0 0 0 1177 | 0 0 0 1178 | 0 0 0 1179 | ] 1180 | [ 1181 | 0 0 0 0 0 0 0 1182 | 0 0 0 0 0 0 0 1183 | 0 0 0 0 0 0 0 1184 | 0 0 0 0 0 0 0 1185 | 0 0 0 0 0 0 0 1186 | 0 0 0 0 0 0 0 1187 | 0 0 0 0 0 0 0 1188 | 0 0 0 0 0 0 0 1189 | 0 0 0 0 0 0 0 1190 | 0 0 0 0 0 0 0 1191 | ] 1192 | [ 1193 | 0 1194 | 0 1195 | 0 1196 | 0 1197 | 0 1198 | 0 1199 | 0 1200 | 0 1201 | 0 1202 | 0 1203 | 0 1204 | 0 1205 | 0 1206 | 0 1207 | 0 1208 | 0 1209 | 0 1210 | 0 1211 | 0 1212 | 0 1213 | 0 1214 | 0 1215 | 0 1216 | 0 1217 | 0 1218 | 0 1219 | 0 1220 | 0 1221 | 0 1222 | 0 1223 | 0 1224 | 0 1225 | 0 1226 | 0 1227 | 0 1228 | 0 1229 | 0 1230 | 0 1231 | 0 1232 | 0 1233 | 0 1234 | 0 1235 | 0 1236 | 0 1237 | 0 1238 | 0 1239 | 0 1240 | 0 1241 | 0 1242 | 0 1243 | 0 1244 | 0 1245 | 0 1246 | 0 1247 | 0 1248 | 0 1249 | 0 1250 | 0 1251 | 0 1252 | 0 1253 | 0 1254 | 0 1255 | 0 1256 | 0 1257 | 0 1258 | 0 1259 | 0 1260 | 0 1261 | 0 1262 | 0 1263 | 0 1264 | ] 1265 | [ 1266 | 0 0 0 0 0 0 0 0 0 1267 | 0 0 0 0 0 0 0 0 0 1268 | 0 0 0 0 0 0 0 0 0 1269 | 0 0 0 0 0 0 0 0 0 1270 | 0 0 0 0 0 0 0 0 0 1271 | 0 0 0 0 0 0 0 0 0 1272 | 0 0 0 0 0 0 0 0 0 1273 | 0 0 0 0 0 0 0 0 0 1274 | ] 1275 | [ 1276 | 0 1277 | 0 1278 | 0 1279 | 0 1280 | 0 1281 | 0 1282 | 0 1283 | 0 1284 | 0 1285 | 0 1286 | 0 1287 | 0 1288 | 0 1289 | 0 1290 | 0 1291 | 0 1292 | 0 1293 | 0 1294 | 0 1295 | 0 1296 | 0 1297 | 0 1298 | 0 1299 | 0 1300 | 0 1301 | 0 1302 | 0 1303 | 0 1304 | 0 1305 | 0 1306 | 0 1307 | 0 1308 | 0 1309 | 0 1310 | 0 1311 | 0 1312 | 0 1313 | 0 1314 | 0 1315 | 0 1316 | 0 1317 | 0 1318 | 0 1319 | 0 1320 | 0 1321 | 0 1322 | 0 1323 | 0 1324 | 0 1325 | 0 1326 | 0 1327 | 0 1328 | 0 1329 | 0 1330 | 0 1331 | 0 1332 | 0 1333 | 0 1334 | 0 1335 | 0 1336 | 0 1337 | 0 1338 | 0 1339 | 0 1340 | 0 1341 | 0 1342 | 0 1343 | 0 1344 | 0 1345 | 0 1346 | 0 1347 | 0 1348 | 0 1349 | ] 1350 | [ 1351 | 0 0 1352 | 0 0 1353 | 0 0 1354 | 0 0 1355 | 0 0 1356 | 0 0 1357 | 0 0 1358 | 0 0 1359 | 0 0 1360 | 0 0 1361 | 0 0 1362 | 0 0 1363 | 0 0 1364 | 0 0 1365 | 0 0 1366 | 0 0 1367 | 0 0 1368 | 0 0 1369 | 0 0 1370 | 0 0 1371 | 0 0 1372 | 0 0 1373 | 0 0 1374 | 0 0 1375 | 0 0 1376 | 0 0 1377 | 0 0 1378 | 0 0 1379 | 0 0 1380 | 0 0 1381 | 0 0 1382 | 0 0 1383 | 0 0 1384 | 0 0 1385 | 0 0 1386 | 0 0 1387 | 0 0 1388 | ] 1389 | [ 1390 | 0 0 0 0 0 1391 | 0 0 0 0 0 1392 | 0 0 0 0 0 1393 | 0 0 0 0 0 1394 | 0 0 0 0 0 1395 | 0 0 0 0 0 1396 | 0 0 0 0 0 1397 | 0 0 0 0 0 1398 | 0 0 0 0 0 1399 | 0 0 0 0 0 1400 | 0 0 0 0 0 1401 | 0 0 0 0 0 1402 | 0 0 0 0 0 1403 | 0 0 0 0 0 1404 | 0 0 0 0 0 1405 | ] 1406 | [ 1407 | 0 0 0 0 1408 | 0 0 0 0 1409 | 0 0 0 0 1410 | 0 0 0 0 1411 | 0 0 0 0 1412 | 0 0 0 0 1413 | 0 0 0 0 1414 | 0 0 0 0 1415 | 0 0 0 0 1416 | 0 0 0 0 1417 | 0 0 0 0 1418 | 0 0 0 0 1419 | 0 0 0 0 1420 | 0 0 0 0 1421 | 0 0 0 0 1422 | 0 0 0 0 1423 | 0 0 0 0 1424 | 0 0 0 0 1425 | 0 0 0 0 1426 | ] 1427 | [ 1428 | 0 0 0 0 0 0 0 1429 | 0 0 0 0 0 0 0 1430 | 0 0 0 0 0 0 0 1431 | 0 0 0 0 0 0 0 1432 | 0 0 0 0 0 0 0 1433 | 0 0 0 0 0 0 0 1434 | 0 0 0 0 0 0 0 1435 | 0 0 0 0 0 0 0 1436 | 0 0 0 0 0 0 0 1437 | 0 0 0 0 0 0 0 1438 | 0 0 0 0 0 0 0 1439 | ] 1440 | [ 1441 | 0 0 0 0 0 0 1442 | 0 0 0 0 0 0 1443 | 0 0 0 0 0 0 1444 | 0 0 0 0 0 0 1445 | 0 0 0 0 0 0 1446 | 0 0 0 0 0 0 1447 | 0 0 0 0 0 0 1448 | 0 0 0 0 0 0 1449 | 0 0 0 0 0 0 1450 | 0 0 0 0 0 0 1451 | 0 0 0 0 0 0 1452 | 0 0 0 0 0 0 1453 | 0 0 0 0 0 0 1454 | ] 1455 | [ 1456 | 0 1457 | 0 1458 | 0 1459 | 0 1460 | 0 1461 | 0 1462 | 0 1463 | 0 1464 | 0 1465 | 0 1466 | 0 1467 | 0 1468 | 0 1469 | 0 1470 | 0 1471 | 0 1472 | 0 1473 | 0 1474 | 0 1475 | 0 1476 | 0 1477 | 0 1478 | 0 1479 | 0 1480 | 0 1481 | 0 1482 | 0 1483 | 0 1484 | 0 1485 | 0 1486 | 0 1487 | 0 1488 | 0 1489 | 0 1490 | 0 1491 | 0 1492 | 0 1493 | 0 1494 | 0 1495 | 0 1496 | 0 1497 | 0 1498 | 0 1499 | 0 1500 | 0 1501 | 0 1502 | 0 1503 | 0 1504 | 0 1505 | 0 1506 | 0 1507 | 0 1508 | 0 1509 | 0 1510 | 0 1511 | 0 1512 | 0 1513 | 0 1514 | 0 1515 | 0 1516 | 0 1517 | 0 1518 | 0 1519 | 0 1520 | 0 1521 | 0 1522 | 0 1523 | 0 1524 | 0 1525 | 0 1526 | 0 1527 | 0 1528 | 0 1529 | 0 1530 | 0 1531 | 0 1532 | 0 1533 | 0 1534 | 0 1535 | ] 1536 | [ 1537 | 0 0 0 0 0 0 0 0 1538 | 0 0 0 0 0 0 0 0 1539 | 0 0 0 0 0 0 0 0 1540 | 0 0 0 0 0 0 0 0 1541 | 0 0 0 0 0 0 0 0 1542 | 0 0 0 0 0 0 0 0 1543 | 0 0 0 0 0 0 0 0 1544 | 0 0 0 0 0 0 0 0 1545 | 0 0 0 0 0 0 0 0 1546 | 0 0 0 0 0 0 0 0 1547 | ] 1548 | [ 1549 | 0 0 0 0 0 0 0 0 0 1550 | 0 0 0 0 0 0 0 0 0 1551 | 0 0 0 0 0 0 0 0 0 1552 | 0 0 0 0 0 0 0 0 0 1553 | 0 0 0 0 0 0 0 0 0 1554 | 0 0 0 0 0 0 0 0 0 1555 | 0 0 0 0 0 0 0 0 0 1556 | 0 0 0 0 0 0 0 0 0 1557 | 0 0 0 0 0 0 0 0 0 1558 | ] 1559 | [ 1560 | 0 0 1561 | 0 0 1562 | 0 0 1563 | 0 0 1564 | 0 0 1565 | 0 0 1566 | 0 0 1567 | 0 0 1568 | 0 0 1569 | 0 0 1570 | 0 0 1571 | 0 0 1572 | 0 0 1573 | 0 0 1574 | 0 0 1575 | 0 0 1576 | 0 0 1577 | 0 0 1578 | 0 0 1579 | 0 0 1580 | 0 0 1581 | 0 0 1582 | 0 0 1583 | 0 0 1584 | 0 0 1585 | 0 0 1586 | 0 0 1587 | 0 0 1588 | 0 0 1589 | 0 0 1590 | 0 0 1591 | 0 0 1592 | 0 0 1593 | 0 0 1594 | 0 0 1595 | 0 0 1596 | 0 0 1597 | 0 0 1598 | 0 0 1599 | 0 0 1600 | 0 0 1601 | ] 1602 | [ 1603 | 0 1604 | 0 1605 | 0 1606 | 0 1607 | 0 1608 | 0 1609 | 0 1610 | 0 1611 | 0 1612 | 0 1613 | 0 1614 | 0 1615 | 0 1616 | 0 1617 | 0 1618 | 0 1619 | 0 1620 | 0 1621 | 0 1622 | 0 1623 | 0 1624 | 0 1625 | 0 1626 | 0 1627 | 0 1628 | 0 1629 | 0 1630 | 0 1631 | 0 1632 | 0 1633 | 0 1634 | 0 1635 | 0 1636 | 0 1637 | 0 1638 | 0 1639 | 0 1640 | 0 1641 | 0 1642 | 0 1643 | 0 1644 | 0 1645 | 0 1646 | 0 1647 | 0 1648 | 0 1649 | 0 1650 | 0 1651 | 0 1652 | 0 1653 | 0 1654 | 0 1655 | 0 1656 | 0 1657 | 0 1658 | 0 1659 | 0 1660 | 0 1661 | 0 1662 | 0 1663 | 0 1664 | 0 1665 | 0 1666 | 0 1667 | 0 1668 | 0 1669 | 0 1670 | 0 1671 | 0 1672 | 0 1673 | 0 1674 | 0 1675 | 0 1676 | 0 1677 | 0 1678 | 0 1679 | 0 1680 | 0 1681 | 0 1682 | 0 1683 | 0 1684 | 0 1685 | 0 1686 | ] 1687 | [ 1688 | 0 0 0 0 0 0 0 1689 | 0 0 0 0 0 0 0 1690 | 0 0 0 0 0 0 0 1691 | 0 0 0 0 0 0 0 1692 | 0 0 0 0 0 0 0 1693 | 0 0 0 0 0 0 0 1694 | 0 0 0 0 0 0 0 1695 | 0 0 0 0 0 0 0 1696 | 0 0 0 0 0 0 0 1697 | 0 0 0 0 0 0 0 1698 | 0 0 0 0 0 0 0 1699 | 0 0 0 0 0 0 0 1700 | ] 1701 | [ 1702 | 0 0 0 0 0 1703 | 0 0 0 0 0 1704 | 0 0 0 0 0 1705 | 0 0 0 0 0 1706 | 0 0 0 0 0 1707 | 0 0 0 0 0 1708 | 0 0 0 0 0 1709 | 0 0 0 0 0 1710 | 0 0 0 0 0 1711 | 0 0 0 0 0 1712 | 0 0 0 0 0 1713 | 0 0 0 0 0 1714 | 0 0 0 0 0 1715 | 0 0 0 0 0 1716 | 0 0 0 0 0 1717 | 0 0 0 0 0 1718 | 0 0 0 0 0 1719 | ] 1720 | [ 1721 | 0 0 1722 | 0 0 1723 | 0 0 1724 | 0 0 1725 | 0 0 1726 | 0 0 1727 | 0 0 1728 | 0 0 1729 | 0 0 1730 | 0 0 1731 | 0 0 1732 | 0 0 1733 | 0 0 1734 | 0 0 1735 | 0 0 1736 | 0 0 1737 | 0 0 1738 | 0 0 1739 | 0 0 1740 | 0 0 1741 | 0 0 1742 | 0 0 1743 | 0 0 1744 | 0 0 1745 | 0 0 1746 | 0 0 1747 | 0 0 1748 | 0 0 1749 | 0 0 1750 | 0 0 1751 | 0 0 1752 | 0 0 1753 | 0 0 1754 | 0 0 1755 | 0 0 1756 | 0 0 1757 | 0 0 1758 | 0 0 1759 | 0 0 1760 | 0 0 1761 | 0 0 1762 | 0 0 1763 | 0 0 1764 | ] 1765 | [ 1766 | 0 0 0 1767 | 0 0 0 1768 | 0 0 0 1769 | 0 0 0 1770 | 0 0 0 1771 | 0 0 0 1772 | 0 0 0 1773 | 0 0 0 1774 | 0 0 0 1775 | 0 0 0 1776 | 0 0 0 1777 | 0 0 0 1778 | 0 0 0 1779 | 0 0 0 1780 | 0 0 0 1781 | 0 0 0 1782 | 0 0 0 1783 | 0 0 0 1784 | 0 0 0 1785 | 0 0 0 1786 | 0 0 0 1787 | 0 0 0 1788 | 0 0 0 1789 | 0 0 0 1790 | 0 0 0 1791 | 0 0 0 1792 | 0 0 0 1793 | 0 0 0 1794 | 0 0 0 1795 | ] 1796 | [ 1797 | 0 0 0 0 0 0 0 0 1798 | 0 0 0 0 0 0 0 0 1799 | 0 0 0 0 0 0 0 0 1800 | 0 0 0 0 0 0 0 0 1801 | 0 0 0 0 0 0 0 0 1802 | 0 0 0 0 0 0 0 0 1803 | 0 0 0 0 0 0 0 0 1804 | 0 0 0 0 0 0 0 0 1805 | 0 0 0 0 0 0 0 0 1806 | 0 0 0 0 0 0 0 0 1807 | 0 0 0 0 0 0 0 0 1808 | ] 1809 | [ 1810 | 0 1811 | 0 1812 | 0 1813 | 0 1814 | 0 1815 | 0 1816 | 0 1817 | 0 1818 | 0 1819 | 0 1820 | 0 1821 | 0 1822 | 0 1823 | 0 1824 | 0 1825 | 0 1826 | 0 1827 | 0 1828 | 0 1829 | 0 1830 | 0 1831 | 0 1832 | 0 1833 | 0 1834 | 0 1835 | 0 1836 | 0 1837 | 0 1838 | 0 1839 | 0 1840 | 0 1841 | 0 1842 | 0 1843 | 0 1844 | 0 1845 | 0 1846 | 0 1847 | 0 1848 | 0 1849 | 0 1850 | 0 1851 | 0 1852 | 0 1853 | 0 1854 | 0 1855 | 0 1856 | 0 1857 | 0 1858 | 0 1859 | 0 1860 | 0 1861 | 0 1862 | 0 1863 | 0 1864 | 0 1865 | 0 1866 | 0 1867 | 0 1868 | 0 1869 | 0 1870 | 0 1871 | 0 1872 | 0 1873 | 0 1874 | 0 1875 | 0 1876 | 0 1877 | 0 1878 | 0 1879 | 0 1880 | 0 1881 | 0 1882 | 0 1883 | 0 1884 | 0 1885 | 0 1886 | 0 1887 | 0 1888 | 0 1889 | 0 1890 | 0 1891 | 0 1892 | 0 1893 | 0 1894 | 0 1895 | 0 1896 | 0 1897 | 0 1898 | 0 1899 | ] 1900 | [ 1901 | 0 0 0 0 0 0 0 0 0 1902 | 0 0 0 0 0 0 0 0 0 1903 | 0 0 0 0 0 0 0 0 0 1904 | 0 0 0 0 0 0 0 0 0 1905 | 0 0 0 0 0 0 0 0 0 1906 | 0 0 0 0 0 0 0 0 0 1907 | 0 0 0 0 0 0 0 0 0 1908 | 0 0 0 0 0 0 0 0 0 1909 | 0 0 0 0 0 0 0 0 0 1910 | 0 0 0 0 0 0 0 0 0 1911 | ] 1912 | [ 1913 | 0 0 0 0 0 0 0 1914 | 0 0 0 0 0 0 0 1915 | 0 0 0 0 0 0 0 1916 | 0 0 0 0 0 0 0 1917 | 0 0 0 0 0 0 0 1918 | 0 0 0 0 0 0 0 1919 | 0 0 0 0 0 0 0 1920 | 0 0 0 0 0 0 0 1921 | 0 0 0 0 0 0 0 1922 | 0 0 0 0 0 0 0 1923 | 0 0 0 0 0 0 0 1924 | 0 0 0 0 0 0 0 1925 | 0 0 0 0 0 0 0 1926 | ] 1927 | [ 1928 | 0 0 0 0 1929 | 0 0 0 0 1930 | 0 0 0 0 1931 | 0 0 0 0 1932 | 0 0 0 0 1933 | 0 0 0 0 1934 | 0 0 0 0 1935 | 0 0 0 0 1936 | 0 0 0 0 1937 | 0 0 0 0 1938 | 0 0 0 0 1939 | 0 0 0 0 1940 | 0 0 0 0 1941 | 0 0 0 0 1942 | 0 0 0 0 1943 | 0 0 0 0 1944 | 0 0 0 0 1945 | 0 0 0 0 1946 | 0 0 0 0 1947 | 0 0 0 0 1948 | 0 0 0 0 1949 | 0 0 0 0 1950 | 0 0 0 0 1951 | ] 1952 | [ 1953 | 0 0 0 1954 | 0 0 0 1955 | 0 0 0 1956 | 0 0 0 1957 | 0 0 0 1958 | 0 0 0 1959 | 0 0 0 1960 | 0 0 0 1961 | 0 0 0 1962 | 0 0 0 1963 | 0 0 0 1964 | 0 0 0 1965 | 0 0 0 1966 | 0 0 0 1967 | 0 0 0 1968 | 0 0 0 1969 | 0 0 0 1970 | 0 0 0 1971 | 0 0 0 1972 | 0 0 0 1973 | 0 0 0 1974 | 0 0 0 1975 | 0 0 0 1976 | 0 0 0 1977 | 0 0 0 1978 | 0 0 0 1979 | 0 0 0 1980 | 0 0 0 1981 | 0 0 0 1982 | 0 0 0 1983 | 0 0 0 1984 | ] 1985 | [ 1986 | 0 0 1987 | 0 0 1988 | 0 0 1989 | 0 0 1990 | 0 0 1991 | 0 0 1992 | 0 0 1993 | 0 0 1994 | 0 0 1995 | 0 0 1996 | 0 0 1997 | 0 0 1998 | 0 0 1999 | 0 0 2000 | 0 0 2001 | 0 0 2002 | 0 0 2003 | 0 0 2004 | 0 0 2005 | 0 0 2006 | 0 0 2007 | 0 0 2008 | 0 0 2009 | 0 0 2010 | 0 0 2011 | 0 0 2012 | 0 0 2013 | 0 0 2014 | 0 0 2015 | 0 0 2016 | 0 0 2017 | 0 0 2018 | 0 0 2019 | 0 0 2020 | 0 0 2021 | 0 0 2022 | 0 0 2023 | 0 0 2024 | 0 0 2025 | 0 0 2026 | 0 0 2027 | 0 0 2028 | 0 0 2029 | 0 0 2030 | 0 0 2031 | 0 0 2032 | 0 0 2033 | ] 2034 | [ 2035 | 0 0 0 0 0 2036 | 0 0 0 0 0 2037 | 0 0 0 0 0 2038 | 0 0 0 0 0 2039 | 0 0 0 0 0 2040 | 0 0 0 0 0 2041 | 0 0 0 0 0 2042 | 0 0 0 0 0 2043 | 0 0 0 0 0 2044 | 0 0 0 0 0 2045 | 0 0 0 0 0 2046 | 0 0 0 0 0 2047 | 0 0 0 0 0 2048 | 0 0 0 0 0 2049 | 0 0 0 0 0 2050 | 0 0 0 0 0 2051 | 0 0 0 0 0 2052 | 0 0 0 0 0 2053 | 0 0 0 0 0 2054 | ] 2055 | [ 2056 | 0 0 0 0 0 0 0 0 2057 | 0 0 0 0 0 0 0 0 2058 | 0 0 0 0 0 0 0 0 2059 | 0 0 0 0 0 0 0 0 2060 | 0 0 0 0 0 0 0 0 2061 | 0 0 0 0 0 0 0 0 2062 | 0 0 0 0 0 0 0 0 2063 | 0 0 0 0 0 0 0 0 2064 | 0 0 0 0 0 0 0 0 2065 | 0 0 0 0 0 0 0 0 2066 | 0 0 0 0 0 0 0 0 2067 | 0 0 0 0 0 0 0 0 2068 | ] 2069 | [ 2070 | 0 2071 | 0 2072 | 0 2073 | 0 2074 | 0 2075 | 0 2076 | 0 2077 | 0 2078 | 0 2079 | 0 2080 | 0 2081 | 0 2082 | 0 2083 | 0 2084 | 0 2085 | 0 2086 | 0 2087 | 0 2088 | 0 2089 | 0 2090 | 0 2091 | 0 2092 | 0 2093 | 0 2094 | 0 2095 | 0 2096 | 0 2097 | 0 2098 | 0 2099 | 0 2100 | 0 2101 | 0 2102 | 0 2103 | 0 2104 | 0 2105 | 0 2106 | 0 2107 | 0 2108 | 0 2109 | 0 2110 | 0 2111 | 0 2112 | 0 2113 | 0 2114 | 0 2115 | 0 2116 | 0 2117 | 0 2118 | 0 2119 | 0 2120 | 0 2121 | 0 2122 | 0 2123 | 0 2124 | 0 2125 | 0 2126 | 0 2127 | 0 2128 | 0 2129 | 0 2130 | 0 2131 | 0 2132 | 0 2133 | 0 2134 | 0 2135 | 0 2136 | 0 2137 | 0 2138 | 0 2139 | 0 2140 | 0 2141 | 0 2142 | 0 2143 | 0 2144 | 0 2145 | 0 2146 | 0 2147 | 0 2148 | 0 2149 | 0 2150 | 0 2151 | 0 2152 | 0 2153 | 0 2154 | 0 2155 | 0 2156 | 0 2157 | 0 2158 | 0 2159 | 0 2160 | 0 2161 | 0 2162 | 0 2163 | 0 2164 | 0 2165 | 0 2166 | 0 2167 | ] 2168 | [ 2169 | 0 0 0 0 0 0 0 2170 | 0 0 0 0 0 0 0 2171 | 0 0 0 0 0 0 0 2172 | 0 0 0 0 0 0 0 2173 | 0 0 0 0 0 0 0 2174 | 0 0 0 0 0 0 0 2175 | 0 0 0 0 0 0 0 2176 | 0 0 0 0 0 0 0 2177 | 0 0 0 0 0 0 0 2178 | 0 0 0 0 0 0 0 2179 | 0 0 0 0 0 0 0 2180 | 0 0 0 0 0 0 0 2181 | 0 0 0 0 0 0 0 2182 | 0 0 0 0 0 0 0 2183 | ] 2184 | [ 2185 | 0 0 0 0 0 0 0 0 0 2186 | 0 0 0 0 0 0 0 0 0 2187 | 0 0 0 0 0 0 0 0 0 2188 | 0 0 0 0 0 0 0 0 0 2189 | 0 0 0 0 0 0 0 0 0 2190 | 0 0 0 0 0 0 0 0 0 2191 | 0 0 0 0 0 0 0 0 0 2192 | 0 0 0 0 0 0 0 0 0 2193 | 0 0 0 0 0 0 0 0 0 2194 | 0 0 0 0 0 0 0 0 0 2195 | 0 0 0 0 0 0 0 0 0 2196 | ] 2197 | ` 2198 | -------------------------------------------------------------------------------- /fmt_test.go: -------------------------------------------------------------------------------- 1 | package ffmt 2 | 3 | import ( 4 | "time" 5 | 6 | "testing" 7 | ) 8 | 9 | func TestMultiPrint(t *testing.T) { 10 | ff := []func(a ...interface{}) string{ 11 | Sputs, 12 | Sp, 13 | Sd, 14 | Sprint, 15 | Spjson, 16 | } 17 | for _, f := range ff { 18 | if f([]interface{}{1, 2}) != f(1, 2) { 19 | t.Fail() 20 | } 21 | } 22 | } 23 | 24 | func TestNewOptional(t *testing.T) { 25 | o := NewOptional(0, 0, 0) 26 | o.Print(testdata) 27 | } 28 | 29 | func TestPrint(t *testing.T) { 30 | Print(testdata) 31 | } 32 | 33 | func TestPuts(t *testing.T) { 34 | Puts(testdata) 35 | } 36 | 37 | func TestP(t *testing.T) { 38 | P(testdata) 39 | } 40 | 41 | func TestPjson(t *testing.T) { 42 | Pjson(testdata) 43 | } 44 | 45 | func TestD(t *testing.T) { 46 | D(testdata) 47 | } 48 | 49 | type bbb struct { 50 | A int 51 | } 52 | 53 | type T struct { 54 | bbb 55 | Msg string 56 | Msg2 string 57 | Msg3 string 58 | msg string 59 | Msgs []string 60 | Stru []struct { 61 | Msg string 62 | AA [8]int 63 | } 64 | Floats [6]float32 65 | Ints [][]int 66 | Maps map[string]string 67 | B bool 68 | T time.Time 69 | TTT interface{} 70 | TTT2 interface{} 71 | Chan interface{} 72 | Fun interface{} 73 | Uintptr uintptr 74 | Self *T 75 | } 76 | 77 | var testdata *T 78 | 79 | func init() { 80 | testdata = &T{ 81 | bbb{}, 82 | "Display a friendly fmt for golang", 83 | "你好", 84 | "hello all hello all hello all hello all hello all hello all ", 85 | "Display ", 86 | []string{"hello", "world", "bey", "bey", "宽字符制表显示正常仅限等宽字体", "效率又降低了", "哈哈哈哈哈啊", "咳咳", "然而并没有什么卵用"}, 87 | []struct { 88 | Msg string 89 | AA [8]int 90 | }{{}, { 91 | "Test", 92 | [8]int{2222, 3333}, 93 | }}, 94 | [6]float32{2.1, 3.3}, 95 | [][]int{{1, 4, 5, 1, 4, 5, 6, 11999, 0}, {3}, {}}, 96 | map[string]string{ 97 | "aa": "hi world", 98 | "bb": "bye world", 99 | "一二三四五12345adcde": "1122334455", 100 | "鱼鱼鱼": "yuyuyu", 101 | }, 102 | true, 103 | time.Now(), 104 | nil, 105 | (*int)(nil), 106 | make(chan int, 10), 107 | Printf, 108 | 0x12345, 109 | nil, 110 | } 111 | testdata.Self = testdata 112 | } 113 | -------------------------------------------------------------------------------- /format.go: -------------------------------------------------------------------------------- 1 | package ffmt 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "regexp" 7 | ) 8 | 9 | func toMap(data interface{}) map[string]string { 10 | var par = map[string]string{} 11 | var val = reflect.ValueOf(data) 12 | val = reflect.Indirect(val) 13 | switch val.Kind() { 14 | case reflect.Map: 15 | for _, k := range val.MapKeys() { 16 | var v = val.MapIndex(k) 17 | par[fmt.Sprint(k.Interface())] = fmt.Sprint(v.Interface()) 18 | } 19 | case reflect.Array, reflect.Slice: 20 | for i := 0; i != val.Len(); i++ { 21 | var v = val.Index(i) 22 | par[fmt.Sprint(i)] = fmt.Sprint(v.Interface()) 23 | } 24 | case reflect.Struct: 25 | var typ = val.Type() 26 | for i := 0; i != typ.NumField(); i++ { 27 | var f = typ.Field(i) 28 | var k = f.Name 29 | var v = val.FieldByName(k) 30 | if v.CanInterface() { 31 | par[k] = fmt.Sprint(v.Interface()) 32 | } 33 | } 34 | } 35 | return par 36 | } 37 | 38 | func formatMap(str string, par map[string]string) string { 39 | return regexp.MustCompile(`({[\w\d]+})`).ReplaceAllStringFunc(str, func(s string) string { 40 | var d, ok = par[s[1:len(s)-1]] 41 | if ok { 42 | return d 43 | } 44 | return s 45 | }) 46 | } 47 | 48 | // Format Format("hello {name}", "ffmt") to "hello ffmt" 49 | func Format(str string, data ...interface{}) string { 50 | par := map[string]string{} 51 | for _, d := range data { 52 | for k, v := range toMap(d) { 53 | par[k] = v 54 | } 55 | } 56 | return formatMap(str, par) 57 | } 58 | -------------------------------------------------------------------------------- /format_test.go: -------------------------------------------------------------------------------- 1 | package ffmt 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestFormat(t *testing.T) { 8 | if Format("hello {name}!", map[string]interface{}{ 9 | "name": "world", 10 | }) != "hello world!" { 11 | t.Fail() 12 | } 13 | } 14 | 15 | func TestFormat2(t *testing.T) { 16 | if Format("hello {Name}!", struct{ Name string }{"world"}) != "hello world!" { 17 | t.Fail() 18 | } 19 | } 20 | 21 | func TestFormat3(t *testing.T) { 22 | if Format("hello {0}!", []string{"world"}) != "hello world!" { 23 | t.Fail() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module gopkg.in/ffmt.v1 2 | 3 | -------------------------------------------------------------------------------- /misc.go: -------------------------------------------------------------------------------- 1 | package ffmt 2 | 3 | import ( 4 | "fmt" 5 | "unicode/utf8" 6 | ) 7 | 8 | // Printf fmt.Printf 9 | var Printf = fmt.Printf 10 | 11 | // Println fmt.Println 12 | var Println = fmt.Println 13 | 14 | func runeWidth(r rune) int { 15 | switch { 16 | case r == utf8.RuneError || r < '\x20': 17 | return 0 18 | 19 | case '\x20' <= r && r < '\u2000': 20 | return 1 21 | 22 | case '\u2000' <= r && r < '\uFF61': 23 | return 2 24 | 25 | case '\uFF61' <= r && r < '\uFFA0': 26 | return 1 27 | 28 | case '\uFFA0' <= r: 29 | return 2 30 | } 31 | 32 | return 0 33 | } 34 | 35 | func strLen(str string) int { 36 | i := 0 37 | for _, v := range str { 38 | i += runeWidth(v) 39 | } 40 | return i 41 | } 42 | 43 | func spac(depth int) string { 44 | b := []byte{} 45 | if depth > 0 { 46 | for i := 0; i != depth; i++ { 47 | b = append(b, Space) 48 | } 49 | } 50 | return string(b) 51 | } 52 | 53 | var space = map[int]string{} 54 | 55 | func spacing(depth int) string { 56 | v, ok := space[depth] 57 | if ok { 58 | return v 59 | } 60 | v = "\n" + spac(depth-1) 61 | space[depth] = v 62 | return v 63 | } 64 | -------------------------------------------------------------------------------- /opt.go: -------------------------------------------------------------------------------- 1 | package ffmt 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "reflect" 7 | ) 8 | 9 | type optional struct { 10 | style style // Format style 11 | depth int // Maximum recursion depth 12 | opt option // Option 13 | } 14 | 15 | // NewOptional ffmt optional 16 | func NewOptional(depth int, b style, opt option) *optional { 17 | return &optional{ 18 | style: b, 19 | opt: opt, 20 | depth: depth, 21 | } 22 | } 23 | 24 | func (s *optional) Fprint(w io.Writer, i ...interface{}) (int, error) { 25 | return fmt.Fprint(w, s.Sprint(i...)) 26 | } 27 | 28 | func (s *optional) Print(i ...interface{}) (int, error) { 29 | return fmt.Print(s.Sprint(i...)) 30 | } 31 | 32 | func (s *optional) Sprint(i ...interface{}) string { 33 | switch len(i) { 34 | case 0: 35 | return "" 36 | case 1: 37 | buf := getBuilder() 38 | defer putBuilder(buf) 39 | sb := &format{ 40 | buf: buf, 41 | filter: map[uintptr]bool{}, 42 | optional: *s, 43 | } 44 | sb.fmt(reflect.ValueOf(i[0]), 0) 45 | sb.buf.WriteByte('\n') 46 | ret := sb.buf.String() 47 | if s.opt.IsCanRowSpan() { 48 | return Align(ret) 49 | } 50 | return ret 51 | default: 52 | return s.Sprint(i) 53 | } 54 | } 55 | 56 | type option uint32 57 | 58 | // Formatted option 59 | const ( 60 | _ option = 1 << (31 - iota) 61 | CanDefaultString // can use .(fmt.Stringer) 62 | CanFilterDuplicate // Filter duplicates 63 | CanRowSpan // Fold line 64 | ) 65 | 66 | func (t option) IsCanDefaultString() bool { 67 | return (t & CanDefaultString) != 0 68 | } 69 | 70 | func (t option) IsCanFilterDuplicate() bool { 71 | return (t & CanFilterDuplicate) != 0 72 | } 73 | 74 | func (t option) IsCanRowSpan() bool { 75 | return (t & CanRowSpan) != 0 76 | } 77 | 78 | type style int 79 | 80 | // Formatted style 81 | const ( 82 | _ style = iota 83 | StyleP // Display type and data 84 | StylePuts // Display data 85 | StylePrint // Display data; string without quotes 86 | StylePjson // The json style display; Do not show private 87 | ) 88 | -------------------------------------------------------------------------------- /puts.go: -------------------------------------------------------------------------------- 1 | package ffmt 2 | 3 | import ( 4 | "io" 5 | ) 6 | 7 | const colSym = ": " 8 | 9 | // Space rune 10 | var Space byte = ' ' 11 | 12 | // p go style display types for debug 13 | var defD = NewOptional(10, StyleP, CanFilterDuplicate|CanRowSpan) 14 | 15 | // D for debug 16 | func D(a ...interface{}) { 17 | MarkStack(1, defD.Sprint(a...)) 18 | } 19 | 20 | // Sd for debug 21 | func Sd(a ...interface{}) string { 22 | return SmarkStack(1, defD.Sprint(a...)) 23 | } 24 | 25 | // P go style display types 26 | var defP = NewOptional(5, StyleP, CanDefaultString|CanFilterDuplicate|CanRowSpan) 27 | 28 | // Fp The go style friendly display types and data to writer 29 | func Fp(w io.Writer, a ...interface{}) (int, error) { 30 | return defP.Fprint(w, a...) 31 | } 32 | 33 | // P The go style friendly display types and data 34 | func P(a ...interface{}) (int, error) { 35 | return defP.Print(a...) 36 | } 37 | 38 | // Sp The go style friendly display types and data to string 39 | func Sp(a ...interface{}) string { 40 | return defP.Sprint(a...) 41 | } 42 | 43 | // Puts go style 44 | var defPuts = NewOptional(5, StylePuts, CanDefaultString|CanFilterDuplicate|CanRowSpan) 45 | 46 | // Fputs The go style friendly to writer 47 | func Fputs(w io.Writer, a ...interface{}) (int, error) { 48 | return defPuts.Fprint(w, a...) 49 | } 50 | 51 | // Puts The go style friendly display 52 | func Puts(a ...interface{}) (int, error) { 53 | return defPuts.Print(a...) 54 | } 55 | 56 | // Sputs The go style friendly to string 57 | func Sputs(a ...interface{}) string { 58 | return defPuts.Sprint(a...) 59 | } 60 | 61 | // Print go style 62 | var defPrint = NewOptional(5, StylePrint, CanDefaultString|CanFilterDuplicate|CanRowSpan) 63 | 64 | // Fprint The go style friendly to writer 65 | func Fprint(w io.Writer, a ...interface{}) (int, error) { 66 | return defPrint.Fprint(w, a...) 67 | } 68 | 69 | // Print The go style friendly display 70 | func Print(a ...interface{}) (int, error) { 71 | return defPrint.Print(a...) 72 | } 73 | 74 | // Sprint The go style friendly to string 75 | func Sprint(a ...interface{}) string { 76 | return defPrint.Sprint(a...) 77 | } 78 | 79 | // Pjson json style 80 | var defPjson = NewOptional(20, StylePjson, CanDefaultString|CanRowSpan) 81 | 82 | // Fpjson The json style friendly display to writer 83 | func Fpjson(w io.Writer, a ...interface{}) (int, error) { 84 | return defPjson.Fprint(w, a...) 85 | } 86 | 87 | // Pjson The json style friendly display 88 | func Pjson(a ...interface{}) (int, error) { 89 | return defPjson.Print(a...) 90 | } 91 | 92 | // Spjson The json style friendly display to string 93 | func Spjson(a ...interface{}) string { 94 | return defPjson.Sprint(a...) 95 | } 96 | -------------------------------------------------------------------------------- /sort.go: -------------------------------------------------------------------------------- 1 | package ffmt 2 | 3 | import ( 4 | "reflect" 5 | "sort" 6 | ) 7 | 8 | type valueSlice []reflect.Value 9 | 10 | func (p valueSlice) Len() int { 11 | return len(p) 12 | } 13 | func (p valueSlice) Less(i, j int) bool { 14 | pi := p[i] 15 | pj := p[j] 16 | for pi.Kind() == reflect.Interface || pi.Kind() == reflect.Ptr { 17 | pi = pi.Elem() 18 | } 19 | for pj.Kind() == reflect.Interface || pj.Kind() == reflect.Ptr { 20 | pj = pj.Elem() 21 | } 22 | if pi.Kind() == pj.Kind() { 23 | switch pi.Kind() { 24 | case reflect.String: 25 | return pi.String() < pj.String() 26 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 27 | return pi.Int() < pj.Int() 28 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 29 | return pi.Uint() < pj.Uint() 30 | case reflect.Float32, reflect.Float64: 31 | return pi.Float() < pj.Float() 32 | default: 33 | return true 34 | } 35 | } 36 | return pi.Kind() > pj.Kind() 37 | } 38 | func (p valueSlice) Swap(i, j int) { 39 | p[i], p[j] = p[j], p[i] 40 | } 41 | 42 | func (p valueSlice) Sort() { 43 | sort.Sort(p) 44 | } 45 | -------------------------------------------------------------------------------- /stack.go: -------------------------------------------------------------------------------- 1 | package ffmt 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | "runtime" 8 | ) 9 | 10 | // MarkStackFull Output stack full 11 | func MarkStackFull() { 12 | for i := 1; ; i++ { 13 | s := SmarkStackFunc(i) 14 | if s == "" { 15 | break 16 | } 17 | fmt.Println(s) 18 | } 19 | } 20 | 21 | // MarkStack Output prefix stack line pos 22 | func MarkStack(skip int, a ...interface{}) { 23 | fmt.Println(append([]interface{}{SmarkStack(skip + 1)}, a...)...) 24 | } 25 | 26 | // Mark Output prefix current line position 27 | func Mark(a ...interface{}) { 28 | MarkStack(1, a...) 29 | } 30 | 31 | // Smark returns Output prefix current line position 32 | func Smark(a ...interface{}) string { 33 | return SmarkStack(1, a...) 34 | } 35 | 36 | var curDir, _ = os.Getwd() 37 | 38 | func getRelativeDirectory(targpath string) string { 39 | targpath = filepath.Clean(targpath) 40 | 41 | if fileName, err := filepath.Rel(curDir, targpath); err == nil && len(fileName) <= len(targpath) { 42 | targpath = fileName 43 | } 44 | 45 | return targpath 46 | } 47 | 48 | // SmarkStack stack information 49 | func SmarkStack(skip int, a ...interface{}) string { 50 | _, fileName, line, ok := runtime.Caller(skip + 1) 51 | if !ok { 52 | return "" 53 | } 54 | fileName = getRelativeDirectory(fileName) 55 | return fmt.Sprintf("%s:%d %s", fileName, line, fmt.Sprint(a...)) 56 | } 57 | 58 | // SmarkStackFunc stack information 59 | func SmarkStackFunc(skip int, a ...interface{}) string { 60 | pc, fileName, line, ok := runtime.Caller(skip + 1) 61 | if !ok { 62 | return "" 63 | } 64 | funcName := runtime.FuncForPC(pc).Name() 65 | funcName = filepath.Base(funcName) 66 | fileName = getRelativeDirectory(fileName) 67 | return fmt.Sprintf("%s:%d %s %s", fileName, line, funcName, fmt.Sprint(a...)) 68 | } 69 | -------------------------------------------------------------------------------- /stack_test.go: -------------------------------------------------------------------------------- 1 | package ffmt 2 | 3 | import "testing" 4 | 5 | func TestMarkStack(t *testing.T) { 6 | MarkStack(2, "hello") 7 | } 8 | 9 | func TestMark(t *testing.T) { 10 | Mark("hello") 11 | } 12 | 13 | func TestMarkStackFull(t *testing.T) { 14 | MarkStackFull() 15 | } 16 | -------------------------------------------------------------------------------- /table.go: -------------------------------------------------------------------------------- 1 | package ffmt 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "strings" 7 | "unicode" 8 | ) 9 | 10 | // ToTable Data to table data 11 | func ToTable(t interface{}, is ...interface{}) [][]string { 12 | r := make([][]string, len(is)+1) 13 | val := reflect.ValueOf(t) 14 | val = reflect.Indirect(val) 15 | typ := val.Type() 16 | switch val.Kind() { 17 | case reflect.Struct: 18 | for i := 0; i != val.NumField(); i++ { 19 | r[0] = append(r[0], typ.Field(i).Name) 20 | } 21 | case reflect.Map: 22 | ks := val.MapKeys() 23 | valueSlice(ks).Sort() 24 | for i := 0; i != len(ks); i++ { 25 | m := ks[i] 26 | if m.Kind() == reflect.Ptr || m.Kind() == reflect.Interface { 27 | m = m.Elem() 28 | } 29 | if m.CanInterface() { 30 | r[0] = append(r[0], fmt.Sprint(m.Interface())) 31 | } 32 | } 33 | default: 34 | return nil 35 | } 36 | 37 | for k, v := range is { 38 | val0 := reflect.ValueOf(v) 39 | val0 = reflect.Indirect(val0) 40 | switch val0.Kind() { 41 | case reflect.Struct: 42 | for i := 0; i != len(r[0]); i++ { 43 | field := val0.FieldByName(r[0][i]) 44 | if field.CanInterface() { 45 | r[k+1] = append(r[k+1], fmt.Sprint(field.Interface())) 46 | } 47 | } 48 | case reflect.Map: 49 | for i := 0; i != len(r[0]); i++ { 50 | vv := val0.MapIndex(reflect.ValueOf(r[0][i])) 51 | if vv.IsValid() { 52 | r[k+1] = append(r[k+1], fmt.Sprint(vv)) 53 | } else { 54 | r[k+1] = append(r[k+1], "") 55 | } 56 | } 57 | default: 58 | return nil 59 | } 60 | } 61 | return r 62 | } 63 | 64 | // FmtTable Format table data 65 | func FmtTable(b [][]string) (ss []string) { 66 | maxs := []int{} 67 | for _, v1 := range b { 68 | for k, v2 := range v1 { 69 | if len(maxs) == k { 70 | maxs = append(maxs, 0) 71 | } 72 | if b := strLen(v2); maxs[k] < b { 73 | maxs[k] = b 74 | } 75 | } 76 | } 77 | buf := getBuilder() 78 | for _, v1 := range b { 79 | buf.Reset() 80 | for k, v2 := range v1 { 81 | buf.WriteString(v2) 82 | ps := maxs[k] - strLen(v2) + 1 83 | for i := 0; i != ps; i++ { 84 | buf.WriteByte(' ') 85 | } 86 | } 87 | ss = append(ss, buf.String()) 88 | } 89 | putBuilder(buf) 90 | return 91 | } 92 | 93 | // TableText table text 94 | func TableText(b string, prefix, split string) string { 95 | rows := []string{} 96 | table := [][]string{} 97 | for _, v := range strings.Split(b, "\n") { 98 | if prefix != "" && !strings.HasPrefix(v, prefix) { 99 | if len(table) != 0 { 100 | rows = append(rows, FmtTable(table)...) 101 | table = table[:0] 102 | } 103 | rows = append(rows, v) 104 | continue 105 | } 106 | 107 | var row []string 108 | ss := strings.Split(v, split) 109 | for i, col := range ss { 110 | if i == 0 { 111 | row = append(row, strings.TrimRightFunc(col, unicode.IsSpace)) 112 | } else { 113 | row = append(row, strings.TrimFunc(col, unicode.IsSpace)) 114 | } 115 | if i != len(ss)-1 { 116 | row[i] = row[i] + split 117 | } 118 | } 119 | table = append(table, row) 120 | } 121 | if len(table) != 0 { 122 | rows = append(rows, FmtTable(table)...) 123 | } 124 | ret := strings.Join(rows, "\n") 125 | return ret 126 | } 127 | -------------------------------------------------------------------------------- /table_test.go: -------------------------------------------------------------------------------- 1 | package ffmt 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | ) 7 | 8 | func TestTable1(t *testing.T) { 9 | b := []struct { 10 | Na string 11 | Ba string 12 | }{ 13 | {"1111", "123123"}, 14 | {"1", "1231233231"}, 15 | {"aaaa", "1231231"}, 16 | } 17 | 18 | out := `Na Ba 19 | 1111 123123 20 | 1 1231233231 21 | aaaa 1231231 22 | aaa3a` 23 | 24 | resu := strings.TrimSpace(strings.Join(FmtTable(ToTable(b[0], b[0], b[1], b[2], map[string]string{ 25 | "Na": "aaa3a", 26 | })), "\n")) 27 | if resu != out { 28 | t.Fatal(resu) 29 | } 30 | } 31 | 32 | func TestTable2(t *testing.T) { 33 | b := []map[string]interface{}{ 34 | {"Na": "1111", "Ba": "123123"}, 35 | {"Na": "1", "Ba": "1231233231"}, 36 | {"Na": "aaaa", "Ba": "1231231"}, 37 | } 38 | 39 | out := `Ba Na 40 | 123123 1111 41 | 1231233231 1 42 | 1231231 aaaa 43 | aaa3a` 44 | 45 | resu := strings.TrimSpace(strings.Join(FmtTable(ToTable(b[0], b[0], b[1], b[2], map[string]string{ 46 | "Na": "aaa3a", 47 | })), "\n")) 48 | if resu != out { 49 | t.Fatal(resu) 50 | } 51 | } 52 | 53 | func TestTableText1(t *testing.T) { 54 | tableData := [][2]string{ 55 | {` 56 | A AA 57 | BBBB B 58 | `, ` 59 | A AA 60 | BBBB B 61 | `}, 62 | } 63 | 64 | for _, v := range tableData { 65 | resu := strings.TrimSpace(TableText(v[0], "", " ")) 66 | if resu != strings.TrimSpace(v[1]) { 67 | t.Fatal(resu) 68 | } 69 | } 70 | } 71 | 72 | func TestTableText2(t *testing.T) { 73 | tableData := [][2]string{ 74 | {` 75 | // A AA 76 | // BBBB B 77 | CC CC 78 | `, ` 79 | // A AA 80 | // BBBB B 81 | CC CC 82 | `}, 83 | } 84 | 85 | for _, v := range tableData { 86 | resu := strings.TrimSpace(TableText(v[0], "//", " ")) 87 | if resu != strings.TrimSpace(v[1]) { 88 | t.Fatal(resu) 89 | } 90 | } 91 | } 92 | --------------------------------------------------------------------------------