github.com/matrixorigin/matrixone@v0.7.0/pkg/vectorize/format/format.go (about) 1 // Copyright 2022 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package format 16 17 import ( 18 "bytes" 19 "strconv" 20 "strings" 21 "unicode" 22 23 "github.com/matrixorigin/matrixone/pkg/common/moerr" 24 ) 25 26 // FormatFunc is the locale format function signature. 27 type FormatFunc func(string, string) (string, error) 28 29 func Format(numbers, precisions, locales []string, rowCount int, constVectors []bool, results []string) error { 30 var err error 31 if constVectors[0] { 32 number := numbers[0] 33 if constVectors[1] { 34 precision := precisions[0] 35 if constVectors[2] { 36 //scalar - scalar - scalar 37 results[0], err = getNumberFormat(number, precision, locales[0]) 38 if err != nil { 39 return err 40 } 41 } else { 42 //scalar - scalar - vector 43 for i := 0; i < rowCount; i++ { 44 results[i], err = getNumberFormat(number, precision, locales[i]) 45 if err != nil { 46 return err 47 } 48 } 49 } 50 } else { 51 if constVectors[2] { 52 locale := locales[0] 53 //scalar - vector - scalar 54 for i := 0; i < rowCount; i++ { 55 results[i], err = getNumberFormat(number, precisions[i], locale) 56 if err != nil { 57 return err 58 } 59 } 60 } else { 61 //scalar - vector - vector 62 for i := 0; i < rowCount; i++ { 63 results[i], err = getNumberFormat(number, precisions[i], locales[i]) 64 if err != nil { 65 return err 66 } 67 } 68 } 69 } 70 } else { 71 if constVectors[1] { 72 precision := precisions[0] 73 if constVectors[2] { 74 locale := locales[0] 75 //vector - scalar - scalar 76 for i := 0; i < rowCount; i++ { 77 results[i], err = getNumberFormat(numbers[i], precision, locale) 78 if err != nil { 79 return err 80 } 81 } 82 } else { 83 //vaetor - scalar - vector 84 for i := 0; i < rowCount; i++ { 85 results[i], err = getNumberFormat(numbers[i], precision, locales[i]) 86 if err != nil { 87 return err 88 } 89 } 90 } 91 } else { 92 if constVectors[2] { 93 locale := locales[0] 94 //vector - vector - scalar 95 for i := 0; i < rowCount; i++ { 96 results[i], err = getNumberFormat(numbers[i], precisions[i], locale) 97 if err != nil { 98 return err 99 } 100 } 101 } else { 102 //vector - vector - vector 103 for i := 0; i < rowCount; i++ { 104 results[i], err = getNumberFormat(numbers[i], precisions[i], locales[i]) 105 if err != nil { 106 return err 107 } 108 } 109 } 110 } 111 } 112 return nil 113 } 114 115 func getNumberFormat(number, precision, locale string) (string, error) { 116 return getFormatFunctionWithLocale(locale)(number, precision) 117 } 118 119 // GetFormatFunctionWithLocate get the format function for sepcific locale. 120 func getFormatFunctionWithLocale(locale string) FormatFunc { 121 formatFunc, exist := localeToFormatFunction[locale] 122 if !exist { 123 return formatENUS 124 } 125 return formatFunc 126 } 127 128 // localeToFormatFunction is the string represent of locale format function. 129 var localeToFormatFunction = map[string]FormatFunc{ 130 //formatENUS 131 "ar_AE": formatENUS, 132 "ar_BH": formatENUS, 133 "ar_DZ": formatENUS, 134 "ar_EG": formatENUS, 135 "ar_IN": formatENUS, 136 "ar_IQ": formatENUS, 137 "ar_JO": formatENUS, 138 "ar_KW": formatENUS, 139 "ar_LB": formatENUS, 140 "ar_LY": formatENUS, 141 "ar_MA": formatENUS, 142 "ar_OM": formatENUS, 143 "ar_QA": formatENUS, 144 "ar_SD": formatENUS, 145 "ar_SY": formatENUS, 146 "ar_TN": formatENUS, 147 "ar_YE": formatENUS, 148 "en_AU": formatENUS, 149 "en_CA": formatENUS, 150 "en_GB": formatENUS, 151 "en_IN": formatENUS, 152 "en_NZ": formatENUS, 153 "en_PH": formatENUS, 154 "en_US": formatENUS, 155 "en_ZA": formatENUS, 156 "en_ZW": formatENUS, 157 "es_DO": formatENUS, 158 "es_GT": formatENUS, 159 "es_HN": formatENUS, 160 "en_MX": formatENUS, 161 "es_NI": formatENUS, 162 "es_PA": formatENUS, 163 "es_PR": formatENUS, 164 "es_SV": formatENUS, 165 "es_US": formatENUS, 166 "gu_IN": formatENUS, 167 "he_IL": formatENUS, 168 "hi_IN": formatENUS, 169 "ja_JP": formatENUS, 170 "ko_KR": formatENUS, 171 "ms_MY": formatENUS, 172 "ta_IN": formatENUS, 173 "te_IN": formatENUS, 174 "th_TH": formatENUS, 175 "ur_PK": formatENUS, 176 "zh_CN": formatENUS, 177 "zh_HK": formatENUS, 178 "zh_TW": formatENUS, 179 180 //formatARSA 181 "ar_SA": formatARSA, 182 "ca_ES": formatARSA, 183 "de_AT": formatARSA, 184 "el_GR": formatARSA, 185 "eu_ES": formatARSA, 186 "fr_FR": formatARSA, 187 "fr_LU": formatARSA, 188 "gl_ES": formatARSA, 189 "hr_HR": formatARSA, 190 "it_IT": formatARSA, 191 "nl_BE": formatARSA, 192 "nl_NL": formatARSA, 193 "pl_PL": formatARSA, 194 "pt_BR": formatARSA, 195 "pt_PT": formatARSA, 196 "sl_SI": formatARSA, 197 "sr_RS": formatARSA, 198 199 //formatBEBY 200 "be_BY": formatBEBY, 201 "da_DK": formatBEBY, 202 "de_BE": formatBEBY, 203 "de_DE": formatBEBY, 204 "de_LU": formatBEBY, 205 "es_AR": formatBEBY, 206 "es_BO": formatBEBY, 207 "es_CL": formatBEBY, 208 "es_CO": formatBEBY, 209 "es_EC": formatBEBY, 210 "es_ES": formatBEBY, 211 "es_PY": formatBEBY, 212 "es_UY": formatBEBY, 213 "es_VE": formatBEBY, 214 "fo_FO": formatBEBY, 215 "hu_HU": formatBEBY, 216 "id_ID": formatBEBY, 217 "is_IS": formatBEBY, 218 "lt_LT": formatBEBY, 219 "mn_MN": formatBEBY, 220 "nb_NO": formatBEBY, 221 "no_NO": formatBEBY, 222 "ru_UA": formatBEBY, 223 "sq_AL": formatBEBY, 224 "tr_TR": formatBEBY, 225 "uk_UA": formatBEBY, 226 "vi_VN": formatBEBY, 227 228 //formatBGBG 229 "bg_BG": formatBGBG, 230 "cs_CZ": formatBGBG, 231 "es_CR": formatBGBG, 232 "et_EE": formatBGBG, 233 "fi_FI": formatBGBG, 234 "lv_LV": formatBGBG, 235 "mk_MK": formatBGBG, 236 "ru_RU": formatBGBG, 237 "sk_SK": formatBGBG, 238 "sv_FI": formatBGBG, 239 "sv_SE": formatBGBG, 240 241 //formatDECH 242 "de_CH": formatDECH, 243 "it_CH": formatDECH, 244 "rm_CH": formatDECH, 245 } 246 247 // format number like 20,000,000.0000 248 func formatENUS(number string, precision string) (string, error) { 249 return format(number, precision, []byte{','}, []byte{'.'}) 250 } 251 252 // format number like 20000000.0000 253 func formatARSA(number string, precision string) (string, error) { 254 return format(number, precision, []byte{}, []byte{'.'}) 255 } 256 257 // format number like 20.000.000,0000 258 func formatBEBY(number string, precision string) (string, error) { 259 return format(number, precision, []byte{'.'}, []byte{','}) 260 } 261 262 // format number like 20 000 000,0000 263 func formatBGBG(number string, precision string) (string, error) { 264 return format(number, precision, []byte{' '}, []byte{','}) 265 } 266 267 // format number like 20'000'000.0000 268 func formatDECH(number string, precision string) (string, error) { 269 return format(number, precision, []byte{'\''}, []byte{'.'}) 270 } 271 272 func format(number string, precision string, comma, decimalPoint []byte) (string, error) { 273 var buffer bytes.Buffer 274 275 if len(number) == 0 { 276 return "", nil 277 } 278 //handle precision 279 if unicode.IsDigit(rune(precision[0])) { 280 for i, v := range precision { 281 if unicode.IsDigit(v) { 282 continue 283 } 284 precision = precision[:i] 285 break 286 } 287 } else { 288 precision = "0" 289 } 290 291 //handle number 292 if number[0] == '-' && number[1] == '.' { 293 number = strings.Replace(number, "-", "-0", 1) 294 } else if number[0] == '.' { 295 number = strings.Replace(number, ".", "0.", 1) 296 } 297 298 if (number[:1] == "-" && !unicode.IsDigit(rune(number[1]))) || 299 (!unicode.IsDigit(rune(number[0])) && number[:1] != "-") { 300 buffer.Write([]byte{'0'}) 301 position, err := strconv.ParseUint(precision, 10, 64) 302 if err == nil && position > 0 { 303 buffer.Write([]byte{'.'}) 304 buffer.WriteString(strings.Repeat("0", int(position))) 305 } 306 return buffer.String(), nil 307 } else if number[:1] == "-" { 308 buffer.Write([]byte{'-'}) 309 number = number[1:] 310 } 311 312 // Check for scientific notition. 313 for _, v := range number { 314 if v == 'E' || v == 'e' { 315 num, err := strconv.ParseFloat(number, 64) 316 if err != nil { 317 return "", err 318 } 319 // Convert to non-scientific notition. 320 number = strconv.FormatFloat(num, 'f', -1, 64) 321 break 322 } 323 } 324 325 for i, v := range number { 326 if unicode.IsDigit(v) { 327 continue 328 } else if i == 1 && number[1] == '.' { 329 continue 330 } else if v == '.' && number[1] != '.' { 331 continue 332 } else { 333 number = number[:i] 334 break 335 } 336 } 337 338 parts := strings.Split(number, ".") 339 340 if len(comma) != 0 { 341 addComma(comma, &buffer, parts[0]) 342 } else { 343 buffer.WriteString(parts[0]) 344 } 345 346 //According to the precision to process the decimal parts 347 position, err := strconv.ParseUint(precision, 10, 64) 348 if err != nil { 349 return "", err 350 } 351 352 if position > 0 { 353 buffer.Write(decimalPoint) 354 if len(parts) == 2 { 355 if uint64(len(parts[1])) == position { 356 buffer.WriteString(parts[1][:position]) 357 } else if uint64(len(parts[1])) > position { 358 //need to cast decimal's length 359 if parts[1][position:position+1] >= "5" { 360 buffer.Reset() 361 floatVar, err := strconv.ParseFloat(parts[0]+"."+parts[1], 64) 362 if err != nil { 363 return "", moerr.NewInvalidArgNoCtx("format parser error", parts[0]+"."+parts[1]) 364 } 365 newNumber := strconv.FormatFloat(floatVar, 'f', int(position), 64) 366 newParts := strings.Split(newNumber, ".") 367 368 if len(comma) != 0 { 369 addComma(comma, &buffer, newParts[0]) 370 } else { 371 buffer.WriteString(newParts[0]) 372 } 373 374 buffer.Write(decimalPoint) 375 buffer.WriteString(newParts[1]) 376 } else { 377 buffer.WriteString(parts[1][:position]) 378 } 379 } else { 380 buffer.WriteString(parts[1]) 381 buffer.WriteString(strings.Repeat("0", int(position)-len(parts[1]))) 382 } 383 } else { 384 buffer.WriteString(strings.Repeat("0", int(position))) 385 } 386 } 387 388 return buffer.String(), nil 389 } 390 391 func addComma(comma []byte, buffer *bytes.Buffer, formatString string) { 392 pos := 0 393 394 //Add foramt comma for Integr parts 395 //If the integer part's length larger than 3 396 if len(formatString)%3 != 0 { 397 pos += len(formatString) % 3 398 buffer.WriteString(formatString[:pos]) 399 buffer.Write(comma) 400 } 401 //Add a format comma every three digits 402 for ; pos < len(formatString); pos += 3 { 403 buffer.WriteString(formatString[pos : pos+3]) 404 buffer.Write(comma) 405 } 406 407 buffer.Truncate(buffer.Len() - 1) 408 409 }