github.com/zhongdalu/gf@v1.0.0/g/text/gstr/gstr_parse.go (about) 1 // Copyright 2018 gf Author(https://github.com/zhongdalu/gf). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/zhongdalu/gf. 6 7 package gstr 8 9 import ( 10 "fmt" 11 "net/url" 12 "strings" 13 ) 14 15 // Parse parses the string into map[string]interface{}. 16 // 17 // f1=m&f2=n -> map[f1:m f2:n] 18 // f[a]=m&f[b]=n -> map[f:map[a:m b:n]] 19 // f[a][a]=m&f[a][b]=n -> map[f:map[a:map[a:m b:n]]] 20 // f[]=m&f[]=n -> map[f:[m n]] 21 // f[a][]=m&f[a][]=n -> map[f:map[a:[m n]]] 22 // f[][]=m&f[][]=n -> map[f:[map[]]] // Currently does not support nested slice. 23 // f=m&f[a]=n -> error 24 // a .[[b=c -> map[a___[b:c] 25 // 26 func Parse(s string) (result map[string]interface{}, err error) { 27 result = make(map[string]interface{}) 28 parts := strings.Split(s, "&") 29 for _, part := range parts { 30 pos := strings.Index(part, "=") 31 if pos <= 0 { 32 continue 33 } 34 key, err := url.QueryUnescape(part[:pos]) 35 if err != nil { 36 return nil, err 37 } 38 for key[0] == ' ' { 39 key = key[1:] 40 } 41 if key == "" || key[0] == '[' { 42 continue 43 } 44 value, err := url.QueryUnescape(part[pos+1:]) 45 if err != nil { 46 return nil, err 47 } 48 // split into multiple keys 49 var keys []string 50 left := 0 51 for i, k := range key { 52 if k == '[' && left == 0 { 53 left = i 54 } else if k == ']' { 55 if left > 0 { 56 if len(keys) == 0 { 57 keys = append(keys, key[:left]) 58 } 59 keys = append(keys, key[left+1:i]) 60 left = 0 61 if i+1 < len(key) && key[i+1] != '[' { 62 break 63 } 64 } 65 } 66 } 67 if len(keys) == 0 { 68 keys = append(keys, key) 69 } 70 // first key 71 first := "" 72 for i, chr := range keys[0] { 73 if chr == ' ' || chr == '.' || chr == '[' { 74 first += "_" 75 } else { 76 first += string(chr) 77 } 78 if chr == '[' { 79 first += keys[0][i+1:] 80 break 81 } 82 } 83 keys[0] = first 84 85 // build nested map 86 if err := build(result, keys, value); err != nil { 87 return nil, err 88 } 89 } 90 return result, nil 91 } 92 93 // build nested map. 94 func build(result map[string]interface{}, keys []string, value interface{}) error { 95 length := len(keys) 96 // trim '," 97 key := strings.Trim(keys[0], "'\"") 98 if length == 1 { 99 result[key] = value 100 return nil 101 } 102 103 // The end is slice. like f[], f[a][] 104 if keys[1] == "" && length == 2 { 105 // todo nested slice 106 if key == "" { 107 return nil 108 } 109 val, ok := result[key] 110 if !ok { 111 result[key] = []interface{}{value} 112 return nil 113 } 114 children, ok := val.([]interface{}) 115 if !ok { 116 return fmt.Errorf("expected type '[]interface{}' for key '%s', but got '%T'", key, val) 117 } 118 result[key] = append(children, value) 119 return nil 120 } 121 122 // The end is slice + map. like f[][a] 123 if keys[1] == "" && length > 2 && keys[2] != "" { 124 val, ok := result[key] 125 if !ok { 126 result[key] = []interface{}{} 127 val = result[key] 128 } 129 children, ok := val.([]interface{}) 130 if !ok { 131 return fmt.Errorf("expected type '[]interface{}' for key '%s', but got '%T'", key, val) 132 } 133 if l := len(children); l > 0 { 134 if child, ok := children[l-1].(map[string]interface{}); ok { 135 if _, ok := child[keys[2]]; !ok { 136 build(child, keys[2:], value) 137 return nil 138 } 139 } 140 } 141 child := map[string]interface{}{} 142 build(child, keys[2:], value) 143 result[key] = append(children, child) 144 return nil 145 } 146 147 // map. like f[a], f[a][b] 148 val, ok := result[key] 149 if !ok { 150 result[key] = map[string]interface{}{} 151 val = result[key] 152 } 153 children, ok := val.(map[string]interface{}) 154 if !ok { 155 return fmt.Errorf("expected type 'map[string]interface{}' for key '%s', but got '%T'", key, val) 156 } 157 if err := build(children, keys[1:], value); err != nil { 158 return err 159 } 160 return nil 161 }