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  }