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  }