github.com/qiniu/dyn@v1.3.0/text/subst.go (about)

     1  package text
     2  
     3  import (
     4  	"fmt"
     5  	"net/url"
     6  	"strconv"
     7  	"strings"
     8  	"syscall"
     9  	"unicode/utf8"
    10  
    11  	"github.com/qiniu/dyn/dyn"
    12  	"github.com/qiniu/dyn/text/internal/encoding/json"
    13  	"github.com/qiniu/x/errors"
    14  )
    15  
    16  const (
    17  	Fmttype_Json    = 1
    18  	Fmttype_Form    = 2
    19  	Fmttype_Text    = 3
    20  	Fmttype_Jsonstr = 4 // 在json的字符串内
    21  )
    22  
    23  // ----------------------------------------------------------
    24  
    25  func AsJsonString(data interface{}) (val string, err error) {
    26  
    27  retry:
    28  	switch v := data.(type) {
    29  	case func() interface{}:
    30  		data = v()
    31  		goto retry
    32  
    33  	default:
    34  		v2, ok2 := dyn.Int(data)
    35  		if ok2 {
    36  			return strconv.FormatInt(v2, 10), nil
    37  		}
    38  		v3, err3 := json.Marshal(data)
    39  		if err3 != nil {
    40  			return "", err3
    41  		}
    42  		val = string(v3)
    43  	}
    44  	return
    45  }
    46  
    47  func AsJsonstrString(data interface{}) (val string, err error) {
    48  
    49  retry:
    50  	switch v := data.(type) {
    51  	case func() interface{}:
    52  		data = v()
    53  		goto retry
    54  
    55  	default:
    56  		v2, ok2 := dyn.Int(data)
    57  		if ok2 {
    58  			return strconv.FormatInt(v2, 10), nil
    59  		}
    60  		v3, err3 := json.Marshal(data)
    61  		if err3 != nil {
    62  			return "", err3
    63  		}
    64  		if v3[0] == '"' {
    65  			v3 = v3[1 : len(v3)-1]
    66  		}
    67  		val = string(v3)
    68  	}
    69  	return
    70  }
    71  
    72  func AsQueryString(data interface{}) (val string, err error) {
    73  
    74  	val, err = AsTextString(data)
    75  	if err == nil {
    76  		val = url.QueryEscape(val)
    77  	}
    78  	return
    79  }
    80  
    81  func AsTextString(data interface{}) (val string, err error) {
    82  
    83  retry:
    84  	switch v := data.(type) {
    85  	case string:
    86  		val = v
    87  
    88  	case func() interface{}:
    89  		data = v()
    90  		goto retry
    91  
    92  	default:
    93  		if data == nil {
    94  			return "", nil
    95  		}
    96  		v2, ok2 := dyn.Int(data)
    97  		if ok2 {
    98  			return strconv.FormatInt(v2, 10), nil
    99  		}
   100  		v3, err3 := json.Marshal(data)
   101  		if err3 != nil {
   102  			return "", err3
   103  		}
   104  		val = string(v3)
   105  	}
   106  	return
   107  }
   108  
   109  func AsString(data interface{}, ft int) (val string, err error) {
   110  
   111  	switch ft {
   112  	case Fmttype_Json:
   113  		return AsJsonString(data)
   114  	case Fmttype_Form:
   115  		return AsQueryString(data)
   116  	case Fmttype_Text:
   117  		return AsTextString(data)
   118  	case Fmttype_Jsonstr:
   119  		return AsJsonstrString(data)
   120  	}
   121  	return "", syscall.EINVAL
   122  }
   123  
   124  func GetAsString(data interface{}, key string, ft int, failIfNotExists bool) (val string, err error) {
   125  
   126  	v, ok := dyn.Get(data, key)
   127  	if !ok {
   128  		if failIfNotExists {
   129  			return "", fmt.Errorf("dyn.Get key `%s`: %w", key, syscall.ENOENT)
   130  		}
   131  		return AsString(nil, ft)
   132  	}
   133  	return AsString(v, ft)
   134  }
   135  
   136  // ----------------------------------------------------------
   137  
   138  func decodeVar(
   139  	b []byte, exprvar string, pos int,
   140  	data interface{}, ft, instring int, failIfNotExists bool) ([]byte, int, error) {
   141  
   142  	if ft == Fmttype_Json && instring != 0 {
   143  		ft = Fmttype_Jsonstr
   144  	}
   145  
   146  	if pos+2 < len(exprvar) {
   147  		start := exprvar[pos+1]
   148  		switch start {
   149  		case '(', '{':
   150  			end := ")"
   151  			if start == '{' {
   152  				end = "}"
   153  			}
   154  			exprleft := exprvar[pos+2:]
   155  			pos2 := strings.Index(exprleft, end)
   156  			if pos2 >= 0 {
   157  				key2 := exprleft[:pos2]
   158  				val2, err2 := GetAsString(data, key2, ft, failIfNotExists)
   159  				if err2 != nil {
   160  					return nil, 0, errors.Info(err2, "expr.Exec - GetAsString failed", key2).Detail(err2)
   161  				}
   162  				return append(b, val2...), len(exprvar) - len(exprleft[pos2+1:]), nil
   163  			}
   164  		}
   165  	}
   166  	if pos+1 < len(exprvar) {
   167  		if exprvar[pos+1] == '$' {
   168  			return append(b, '$'), pos + 2, nil
   169  		}
   170  	}
   171  	return nil, 0, errors.Info(syscall.EINVAL, "expr.Exec - invalid expr", exprvar[pos:])
   172  }
   173  
   174  // ----------------------------------------------------------
   175  
   176  func Subst(exprvar string, data interface{}, ft int, failIfNotExists bool) (v string, err error) {
   177  
   178  	var b []byte
   179  
   180  	instring := 0
   181  	start, pos := 0, 0
   182  	end := len(exprvar)
   183  	for pos < end {
   184  		ch, size := utf8.DecodeRuneInString(exprvar[pos:])
   185  		switch ch {
   186  		case '"':
   187  			instring ^= 1
   188  		case '\\':
   189  			pos += size
   190  			if pos < end {
   191  				_, size = utf8.DecodeRuneInString(exprvar[pos:])
   192  			} else {
   193  				size = 0
   194  			}
   195  		case '$':
   196  			if b == nil {
   197  				b = make([]byte, 0, len(exprvar))
   198  			}
   199  			b = append(b, exprvar[start:pos]...)
   200  			b, pos, err = decodeVar(b, exprvar, pos, data, ft, instring, failIfNotExists)
   201  			if err != nil {
   202  				return
   203  			}
   204  			start, size = pos, 0
   205  		}
   206  		pos += size
   207  	}
   208  
   209  	if start < pos {
   210  		if b == nil {
   211  			return exprvar, nil
   212  		}
   213  		b = append(b, exprvar[start:pos]...)
   214  	}
   215  	return string(b), nil
   216  }
   217  
   218  // ----------------------------------------------------------