github.com/easysoft/zendata@v0.0.0-20240513203326-705bd5a7fd67/internal/pkg/service/expression.go (about) 1 package service 2 3 import ( 4 "fmt" 5 "regexp" 6 "strconv" 7 "strings" 8 9 "github.com/Knetic/govaluate" 10 "github.com/easysoft/zendata/internal/pkg/domain" 11 "github.com/easysoft/zendata/internal/pkg/helper" 12 logUtils "github.com/easysoft/zendata/pkg/utils/log" 13 "github.com/easysoft/zendata/pkg/utils/vari" 14 "github.com/mattn/go-runewidth" 15 ) 16 17 type ExpressionService struct { 18 } 19 20 func (s *ExpressionService) GenExpressionValues(field domain.DefField) (ret []interface{}) { 21 valuesMap := vari.GlobalVars.FieldNameToValuesMap 22 fieldMap := vari.GlobalVars.FieldNameToFieldMap 23 24 exp := field.Value 25 26 reg := regexp.MustCompile(`\$([_,a-z,A-Z][_,a-z,A-Z,0-9]*)`) 27 arr := reg.FindAllStringSubmatch(exp, -1) 28 if arr == nil { 29 return field.Values 30 } 31 32 total := 1 33 typeGrade := map[string]int{ 34 "int": 0, 35 "float": 1, 36 "string": 2, 37 } 38 expressionType := "int" 39 if strings.Contains(exp, "'") { 40 expressionType = "string" 41 } 42 for _, items := range arr { // computer total 43 placeholder := items[0] 44 fieldName := items[1] 45 exp = strings.Replace(exp, placeholder, fieldName, 1) 46 47 size := len(valuesMap[fieldName]) 48 if total < size { 49 total = size 50 } 51 52 // judge type of expression 53 referField := fieldMap[fieldName] 54 tp := s.getValuesType(valuesMap[fieldName], referField.Prefix, referField.Postfix) 55 if typeGrade[tp] > typeGrade[expressionType] { 56 expressionType = tp 57 } 58 } 59 60 for i := 0; i < total; i++ { 61 params := make(map[string]interface{}) 62 63 for _, items := range arr { 64 fieldName := items[1] 65 referValues := valuesMap[fieldName] 66 referField := fieldMap[fieldName] 67 68 valStr := "N/A" 69 var val interface{} 70 if len(referValues) > 0 { 71 valStr = fmt.Sprintf("%v", referValues[i%len(referValues)]) 72 valStr = strings.TrimLeft(valStr, referField.Prefix) 73 valStr = strings.TrimRight(valStr, referField.Postfix) 74 75 val = s.parseValue(valStr, expressionType) 76 } 77 params[fieldName] = val 78 } 79 80 expr, err := govaluate.NewEvaluableExpression(exp) 81 if err != nil { 82 logUtils.PrintErrMsg(err.Error()) 83 ret = append(ret, "ERR") 84 } else { 85 result, err := expr.Evaluate(params) 86 if err != nil { 87 logUtils.PrintErrMsg(err.Error()) 88 } 89 90 mask := "" 91 if expressionType == "int" { 92 mask = "%.0f" 93 } else if expressionType == "float" { 94 mask = "%f" 95 } else { 96 mask = "%s" 97 } 98 99 str := fmt.Sprintf(mask, result) 100 if field.Length > runewidth.StringWidth(str) { 101 str = helper.AddPad(str, field) 102 } 103 str = field.Prefix + str + field.Postfix 104 ret = append(ret, str) 105 } 106 } 107 108 return 109 } 110 111 func (s *ExpressionService) ReplaceVariableValues(exp string, valuesMap map[string][]interface{}) (ret []string) { 112 reg := regexp.MustCompile(`\$\{([_,a-z,A-Z,0-9]+)\}`) 113 arr := reg.FindAllStringSubmatch(exp, -1) 114 115 total := 1 116 for _, items := range arr { // computer total 117 fieldName := items[1] 118 119 size := len(valuesMap[fieldName]) 120 if total < size { 121 total = size 122 } 123 } 124 125 for i := 0; i < total; i++ { 126 item := exp 127 for _, items := range arr { 128 fieldSlot := items[0] 129 fieldName := items[1] 130 referValues := valuesMap[fieldName] 131 referField := vari.GlobalVars.TopFieldMap[fieldName] 132 133 valStr := "N/A" 134 if len(referValues) > 0 { 135 valStr = referValues[i%len(referValues)].(string) 136 valStr = strings.TrimLeft(valStr, referField.Prefix) 137 valStr = strings.TrimRight(valStr, referField.Postfix) 138 } 139 140 item = strings.ReplaceAll(item, fieldSlot, valStr) 141 } 142 143 ret = append(ret, item) 144 } 145 146 return 147 } 148 149 func (s *ExpressionService) getValuesType(values []interface{}, prefix string, postfix string) (tp string) { 150 tool := map[string]int{ 151 "int": 0, 152 "float": 1, 153 "string": 2, 154 } 155 tp = "int" 156 for _, item := range values { 157 valStr := strings.TrimLeft(fmt.Sprintf("%v", item), prefix) 158 valStr = strings.TrimRight(valStr, postfix) 159 _, t := s.getType(valStr) 160 if tool[t] > tool[tp] { 161 tp = t 162 } 163 if tp == "string" { 164 break 165 } 166 } 167 return 168 } 169 170 func (s *ExpressionService) getType(str string) (val interface{}, tp string) { 171 val, errInt := strconv.ParseInt(str, 0, 64) 172 if errInt == nil { 173 tp = "int" 174 return 175 } 176 177 val, errFloat := strconv.ParseFloat(str, 64) 178 if errFloat == nil { 179 tp = "float" 180 return 181 } 182 val = str 183 tp = "string" 184 return 185 } 186 187 func (s *ExpressionService) parseValue(str string, tp string) (val interface{}) { 188 var err error 189 if tp == "int" { 190 val, err = strconv.ParseInt(str, 0, 64) 191 if err != nil { 192 val = 0 193 } 194 } else if tp == "float" { 195 val, err = strconv.ParseFloat(str, 64) 196 if err != nil { 197 val = 0.0 198 } 199 } else { 200 val = str 201 } 202 return 203 }