github.com/gogf/gf@v1.16.9/text/gstr/gstr_parse.go (about) 1 // Copyright GoFrame Author(https://goframe.org). 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/gogf/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 // v1=m&v2=n -> map[v1:m v2:n] 18 // v[a]=m&v[b]=n -> map[v:map[a:m b:n]] 19 // v[a][a]=m&v[a][b]=n -> map[v:map[a:map[a:m b:n]]] 20 // v[]=m&v[]=n -> map[v:[m n]] 21 // v[a][]=m&v[a][]=n -> map[v:map[a:[m n]]] 22 // v[][]=m&v[][]=n -> map[v:[map[]]] // Currently does not support nested slice. 23 // v=m&v[a]=n -> error 24 // a .[[b=c -> map[a___[b:c] 25 // 26 func Parse(s string) (result map[string]interface{}, err error) { 27 if s == "" { 28 return nil, nil 29 } 30 result = make(map[string]interface{}) 31 parts := strings.Split(s, "&") 32 for _, part := range parts { 33 pos := strings.Index(part, "=") 34 if pos <= 0 { 35 continue 36 } 37 key, err := url.QueryUnescape(part[:pos]) 38 if err != nil { 39 return nil, err 40 } 41 for key[0] == ' ' { 42 key = key[1:] 43 } 44 if key == "" || key[0] == '[' { 45 continue 46 } 47 value, err := url.QueryUnescape(part[pos+1:]) 48 if err != nil { 49 return nil, err 50 } 51 // split into multiple keys 52 var keys []string 53 left := 0 54 for i, k := range key { 55 if k == '[' && left == 0 { 56 left = i 57 } else if k == ']' { 58 if left > 0 { 59 if len(keys) == 0 { 60 keys = append(keys, key[:left]) 61 } 62 keys = append(keys, key[left+1:i]) 63 left = 0 64 if i+1 < len(key) && key[i+1] != '[' { 65 break 66 } 67 } 68 } 69 } 70 if len(keys) == 0 { 71 keys = append(keys, key) 72 } 73 // first key 74 first := "" 75 for i, chr := range keys[0] { 76 if chr == ' ' || chr == '.' || chr == '[' { 77 first += "_" 78 } else { 79 first += string(chr) 80 } 81 if chr == '[' { 82 first += keys[0][i+1:] 83 break 84 } 85 } 86 keys[0] = first 87 88 // build nested map 89 if err := build(result, keys, value); err != nil { 90 return nil, err 91 } 92 } 93 return result, nil 94 } 95 96 // build nested map. 97 func build(result map[string]interface{}, keys []string, value interface{}) error { 98 length := len(keys) 99 // trim '," 100 key := strings.Trim(keys[0], "'\"") 101 if length == 1 { 102 result[key] = value 103 return nil 104 } 105 106 // The end is slice. like f[], f[a][] 107 if keys[1] == "" && length == 2 { 108 // TODO nested slice 109 if key == "" { 110 return nil 111 } 112 val, ok := result[key] 113 if !ok { 114 result[key] = []interface{}{value} 115 return nil 116 } 117 children, ok := val.([]interface{}) 118 if !ok { 119 return fmt.Errorf("expected type '[]interface{}' for key '%s', but got '%T'", key, val) 120 } 121 result[key] = append(children, value) 122 return nil 123 } 124 125 // The end is slice + map. like v[][a] 126 if keys[1] == "" && length > 2 && keys[2] != "" { 127 val, ok := result[key] 128 if !ok { 129 result[key] = []interface{}{} 130 val = result[key] 131 } 132 children, ok := val.([]interface{}) 133 if !ok { 134 return fmt.Errorf("expected type '[]interface{}' for key '%s', but got '%T'", key, val) 135 } 136 if l := len(children); l > 0 { 137 if child, ok := children[l-1].(map[string]interface{}); ok { 138 if _, ok := child[keys[2]]; !ok { 139 build(child, keys[2:], value) 140 return nil 141 } 142 } 143 } 144 child := map[string]interface{}{} 145 build(child, keys[2:], value) 146 result[key] = append(children, child) 147 return nil 148 } 149 150 // map, like v[a], v[a][b] 151 val, ok := result[key] 152 if !ok { 153 result[key] = map[string]interface{}{} 154 val = result[key] 155 } 156 children, ok := val.(map[string]interface{}) 157 if !ok { 158 return fmt.Errorf("expected type 'map[string]interface{}' for key '%s', but got '%T'", key, val) 159 } 160 if err := build(children, keys[1:], value); err != nil { 161 return err 162 } 163 return nil 164 }