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 // ----------------------------------------------------------