• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2025 Huawei Device Co., Ltd.
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 #include "locale_config.h"
16 
17 #include <cctype>
18 #include <cmath>
19 #include <new>
20 #include <sstream>
21 #include <tuple>
22 #include "format_utils.h"
23 #include "i18n_hilog.h"
24 #include "locale_helper.h"
25 #include "ohos/init_data.h"
26 #include "parameter.h"
27 #include "unicode/ucurr.h"
28 #include "unicode/uenum.h"
29 #include "unicode/utypes.h"
30 #include "unicode/unumberformatter.h"
31 #include "unicode/stringpiece.h"
32 #include "utils.h"
33 #include "number_format.h"
34 
35 namespace OHOS {
36 namespace Global {
37 namespace I18n {
38 const char* NumberFormat::DEVICE_TYPE_NAME = "const.product.devicetype";
39 std::mutex NumberFormat::numToCurrencyMutex;
40 bool NumberFormat::initISO4217 = false;
41 std::unordered_map<std::string, std::string> NumberFormat::numToCurrency = {};
42 bool NumberFormat::icuInitialized = NumberFormat::Init();
43 static const double DEFAULT_SAMPLE_NUMBER = 12345.67;
44 
45 std::unordered_map<std::string, UNumberUnitWidth> NumberFormat::unitStyle = {
46     { "long", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
47     { "short", UNumberUnitWidth::UNUM_UNIT_WIDTH_SHORT },
48     { "narrow", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW }
49 };
50 
51 std::unordered_map<std::string, UNumberUnitWidth> NumberFormat::currencyStyle = {
52     { "symbol", UNumberUnitWidth::UNUM_UNIT_WIDTH_SHORT },
53     { "code", UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE },
54     { "name", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
55     { "narrowSymbol", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW }
56 };
57 
58 std::unordered_map<std::string, UNumberSignDisplay> NumberFormat::signAutoStyle = {
59     { "auto", UNumberSignDisplay::UNUM_SIGN_AUTO },
60     { "never", UNumberSignDisplay::UNUM_SIGN_NEVER },
61     { "always", UNumberSignDisplay::UNUM_SIGN_ALWAYS },
62     { "exceptZero", UNumberSignDisplay::UNUM_SIGN_EXCEPT_ZERO }
63 };
64 
65 std::unordered_map<std::string, UNumberSignDisplay> NumberFormat::signAccountingStyle = {
66     { "auto", UNumberSignDisplay::UNUM_SIGN_ACCOUNTING },
67     { "never", UNumberSignDisplay::UNUM_SIGN_NEVER },
68     { "always", UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_ALWAYS },
69     { "exceptZero", UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO }
70 };
71 
72 std::unordered_map<std::string, std::string> NumberFormat::measurementSystem = {
73     { "metric", "SI" },
74     { "ussystem", "US" },
75     { "uksystem", "UK" },
76 };
77 
78 std::unordered_map<std::string, UNumberUnitWidth> NumberFormat::defaultUnitStyle = {
79     { "tablet", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
80     { "2in1", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
81     { "tv", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
82     { "pc", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
83     { "wearable", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW },
84     { "liteWearable", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW },
85     { "watch", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW }
86 };
87 
88 std::unordered_map<std::string, UNumberUnitWidth> NumberFormat::defaultCurrencyStyle = {
89     { "wearable", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW },
90     { "liteWearable", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW },
91     { "watch", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW }
92 };
93 
94 std::unordered_map<std::string, UNumberRoundingPriority> NumberFormat::roundingPriorityStyle = {
95     { "auto", UNumberRoundingPriority::UNUM_ROUNDING_PRIORITY_STRICT },
96     { "morePrecision", UNumberRoundingPriority::UNUM_ROUNDING_PRIORITY_RELAXED },
97     { "lessPrecision", UNumberRoundingPriority::UNUM_ROUNDING_PRIORITY_STRICT }
98 };
99 
100 std::unordered_map<std::string, UNumberFormatRoundingMode> NumberFormat::roundingModeStyle = {
101     { "ceil", UNumberFormatRoundingMode::UNUM_ROUND_CEILING },
102     { "floor", UNumberFormatRoundingMode::UNUM_ROUND_FLOOR },
103     { "expand", UNumberFormatRoundingMode::UNUM_ROUND_UP },
104     { "trunc", UNumberFormatRoundingMode::UNUM_ROUND_DOWN },
105     { "halfCeil", UNumberFormatRoundingMode::UNUM_ROUND_HALF_CEILING },
106     { "halfFloor", UNumberFormatRoundingMode::UNUM_ROUND_HALF_FLOOR },
107     { "halfExpand", UNumberFormatRoundingMode::UNUM_ROUND_HALFUP },
108     { "halfTrunc", UNumberFormatRoundingMode::UNUM_ROUND_HALFDOWN },
109     { "halfEven", UNumberFormatRoundingMode::UNUM_ROUND_HALFEVEN },
110 };
111 
112 std::vector<size_t> NumberFormat::roundingIncrementList = {
113     1, 2, 5, 10, 20, 25, 50, 100, 200, 250, 500, 1000, 2000, 2500, 5000
114 };
115 
116 std::map<std::string, std::string> NumberFormat::RelativeTimeFormatConfigs = {
117     { "numeric", "auto" }
118 };
119 
120 std::unordered_map<std::string, int> NumberFormat::defaultCurrencyFractionMap = {
121     { "BHD", 3 },
122     { "XOF", 0 },
123     { "BIF", 0 },
124     { "XAF", 0 },
125     { "CLP", 0 },
126     { "CLF", 4 },
127     { "KMF", 0 },
128     { "DJF", 0 },
129     { "XPF", 0 },
130     { "GNF", 0 },
131     { "ISK", 0 },
132     { "IQD", 3 },
133     { "JPY", 0 },
134     { "JOD", 3 },
135     { "KRW", 0 },
136     { "KWD", 3 },
137     { "LYD", 3 },
138     { "OMR", 3 },
139     { "PYG", 0 },
140     { "RWF", 0 },
141     { "TND", 3 },
142     { "UGX", 0 },
143     { "UYI", 0 },
144     { "UYW", 4 },
145     { "VUV", 0 },
146     { "VND", 0 },
147 };
148 
149 static std::unordered_set<std::string> UNIT_USAGE_FILE = {
150     "size-file-byte",
151     "size-shortfile-byte"
152 };
153 
154 static std::unordered_set<std::string> UNIT_USAGE_TEMPERATURE = {
155     "temperature",
156     "temperature-person",
157     "temperature-weather"
158 };
159 
NumberFormat(const std::vector<std::string> & localeTags,std::map<std::string,std::string> & configs)160 NumberFormat::NumberFormat(const std::vector<std::string> &localeTags, std::map<std::string, std::string> &configs)
161 {
162     SetDefaultStyle();
163     ResolveLocaleTags(localeTags, configs);
164     std::string systemLocale = LocaleConfig::GetEffectiveLocale();
165     CreateNumberFormatWithDefaultLocale(systemLocale, configs);
166 }
167 
NumberFormat(const std::vector<std::string> & localeTags,std::map<std::string,std::string> & configs,bool flag)168 NumberFormat::NumberFormat(const std::vector<std::string> &localeTags,
169     std::map<std::string, std::string> &configs, bool flag)
170 {
171     fromArkTs = flag;
172     ResolveLocaleTags(localeTags, configs);
173     std::string defaultLocale = LocaleHelper::DefaultLocale();
174     CreateNumberFormatWithDefaultLocale(defaultLocale, configs);
175 }
176 
ResolveLocaleTags(const std::vector<std::string> & localeTags,std::map<std::string,std::string> & configs)177 void NumberFormat::ResolveLocaleTags(const std::vector<std::string> &localeTags,
178     std::map<std::string, std::string> &configs)
179 {
180     UErrorCode status = U_ZERO_ERROR;
181     std::unique_ptr<icu::LocaleBuilder> builder = nullptr;
182     builder = std::make_unique<icu::LocaleBuilder>();
183     ParseConfigs(configs);
184     for (size_t i = 0; i < localeTags.size(); i++) {
185         std::string curLocale = LocaleConfig::RemoveCustExtParam(localeTags[i]);
186         locale = icu::Locale::forLanguageTag(icu::StringPiece(curLocale), status);
187         if (U_FAILURE(status)) {
188             status = U_ZERO_ERROR;
189             continue;
190         }
191         if (LocaleInfo::allValidLocales.count(locale.getLanguage()) > 0) {
192             localeInfo = std::make_unique<LocaleInfo>(curLocale, configs);
193             CreateRelativeTimeFormat(localeTags[i]);
194             if (!localeInfo->InitSuccess()) {
195                 continue;
196             }
197             locale = localeInfo->GetLocale();
198             localeBaseName = localeInfo->GetBaseName();
199             icu::MeasureUnit::getAvailable(unitArray, MAX_UNIT_NUM, status);
200             if (U_FAILURE(status)) {
201                 status = U_ZERO_ERROR;
202                 continue;
203             }
204             createSuccess = true;
205             ParseExtParam(localeTags[i]);
206             break;
207         }
208     }
209 }
210 
CreateNumberFormatWithDefaultLocale(const std::string & systemLocale,std::map<std::string,std::string> & configs)211 void NumberFormat::CreateNumberFormatWithDefaultLocale(const std::string &systemLocale,
212     std::map<std::string, std::string> &configs)
213 {
214     if (!createSuccess) {
215         std::string curLocale = LocaleConfig::RemoveCustExtParam(systemLocale);
216         localeInfo = std::make_unique<LocaleInfo>(curLocale, configs);
217         CreateRelativeTimeFormat(systemLocale);
218         if (localeInfo != nullptr && localeInfo->InitSuccess()) {
219             locale = localeInfo->GetLocale();
220             localeBaseName = localeInfo->GetBaseName();
221             UErrorCode status = U_ZERO_ERROR;
222             icu::MeasureUnit::getAvailable(unitArray, MAX_UNIT_NUM, status);
223             if (U_SUCCESS(status)) {
224                 createSuccess = true;
225                 ParseExtParam(systemLocale);
226             }
227         }
228     }
229     if (createSuccess) {
230         InitNumberFormat();
231     }
232 }
233 
~NumberFormat()234 NumberFormat::~NumberFormat()
235 {
236 }
237 
InitNumberFormat()238 void NumberFormat::InitNumberFormat()
239 {
240     icu::number::UnlocalizedNumberFormatter tempFormatter = icu::number::NumberFormatter::with();
241     InitProperties(tempFormatter);
242     styleFormatter = tempFormatter;
243     numberFormat = tempFormatter.locale(locale);
244     numberRangeFormat = icu::number::NumberRangeFormatter::with()
245         .numberFormatterBoth(tempFormatter)
246         .locale(locale);
247 }
248 
CreateRelativeTimeFormat(const std::string & locale)249 void NumberFormat::CreateRelativeTimeFormat(const std::string& locale)
250 {
251     if (unitUsage == "elapsed-time-second") {
252         std::vector<std::string> locales = { locale };
253         relativeTimeFormat = std::make_unique<RelativeTimeFormat>(locales,
254             RelativeTimeFormatConfigs);
255     }
256 }
257 
InitProperties(icu::number::UnlocalizedNumberFormatter & formatter)258 void NumberFormat::InitProperties(icu::number::UnlocalizedNumberFormatter &formatter)
259 {
260     InitNumberPattern(formatter);
261     InitCurrencyProperties(formatter);
262     InitPercentStyleProperties(formatter);
263     InitUnitProperties(formatter);
264     InitUseGroupingProperties(formatter);
265     InitSignProperties(formatter);
266     InitNotationProperties(formatter);
267     InitDigitsProperties(formatter);
268 }
269 
InitNumberPattern(icu::number::UnlocalizedNumberFormatter & formatter)270 void NumberFormat::InitNumberPattern(icu::number::UnlocalizedNumberFormatter &formatter)
271 {
272     UErrorCode status = U_ZERO_ERROR;
273     icu::Locale icuLocale = icu::Locale::forLanguageTag(effectiveLocale.c_str(), status);
274     if (U_FAILURE(status)) {
275         HILOG_ERROR_I18N("NumberFormat::InitNumberPattern: Create icu::Locale failed.");
276         return;
277     }
278     icu::DecimalFormatSymbols* decimalFormatSymbols = new icu::DecimalFormatSymbols(icuLocale, status);
279     if (U_FAILURE(status) || decimalFormatSymbols == nullptr) {
280         delete decimalFormatSymbols;
281         HILOG_ERROR_I18N("NumberFormat::InitNumberPattern: Create icu::DecimalFormatSymbols failed.");
282         return;
283     }
284     if (groupingSymbol.empty()) {
285         formatter = formatter.grouping(UNumberGroupingStrategy::UNUM_GROUPING_OFF);
286     } else {
287         decimalFormatSymbols->setSymbol(icu::DecimalFormatSymbols::ENumberFormatSymbol::kGroupingSeparatorSymbol,
288             groupingSymbol.c_str());
289     }
290     if (!decimalSymbol.empty()) {
291         decimalFormatSymbols->setSymbol(icu::DecimalFormatSymbols::ENumberFormatSymbol::kDecimalSeparatorSymbol,
292             decimalSymbol.c_str());
293     }
294     formatter = formatter.symbols(*decimalFormatSymbols);
295     delete decimalFormatSymbols;
296 }
297 
InitCurrencyProperties(icu::number::UnlocalizedNumberFormatter & formatter)298 void NumberFormat::InitCurrencyProperties(icu::number::UnlocalizedNumberFormatter &formatter)
299 {
300     if (!currency.empty()) {
301         UErrorCode status = U_ZERO_ERROR;
302         icu::CurrencyUnit currencyUnit(icu::UnicodeString(currency.c_str()).getBuffer(), status);
303         if (U_FAILURE(status)) {
304             HILOG_ERROR_I18N("NumberFormat::InitCurrencyProperties: Create currency unit failed.");
305             return;
306         }
307         formatter = formatter.unit(currencyUnit);
308         if (currencyDisplay != UNumberUnitWidth::UNUM_UNIT_WIDTH_SHORT) {
309             formatter = formatter.unitWidth(currencyDisplay);
310         }
311     }
312 }
313 
InitPercentStyleProperties(icu::number::UnlocalizedNumberFormatter & formatter)314 void NumberFormat::InitPercentStyleProperties(icu::number::UnlocalizedNumberFormatter &formatter)
315 {
316     if (!styleString.empty() && styleString == "percent") {
317         formatter = formatter.unit(icu::NoUnit::percent())
318             .scale(icu::number::Scale::powerOfTen(2)) // 2 is the power of ten
319             .precision(icu::number::Precision::fixedFraction(0));
320     }
321 }
322 
InitUseGroupingProperties(icu::number::UnlocalizedNumberFormatter & formatter)323 void NumberFormat::InitUseGroupingProperties(icu::number::UnlocalizedNumberFormatter &formatter)
324 {
325     if (!useGrouping.empty()) {
326         UNumberGroupingStrategy groupingStrategy = (useGrouping == "true") ?
327             UNumberGroupingStrategy::UNUM_GROUPING_AUTO : UNumberGroupingStrategy::UNUM_GROUPING_OFF;
328         formatter = formatter.grouping(groupingStrategy);
329     }
330 }
331 
InitNotationProperties(icu::number::UnlocalizedNumberFormatter & formatter)332 void NumberFormat::InitNotationProperties(icu::number::UnlocalizedNumberFormatter &formatter)
333 {
334     if (!notationString.empty()) {
335         formatter = formatter.notation(notation);
336     }
337 }
338 
InitSignProperties(icu::number::UnlocalizedNumberFormatter & formatter)339 void NumberFormat::InitSignProperties(icu::number::UnlocalizedNumberFormatter &formatter)
340 {
341     if (!currencySign.empty() || !signDisplayString.empty()) {
342         formatter = formatter.sign(signDisplay);
343     }
344 }
345 
InitUnitProperties(icu::number::UnlocalizedNumberFormatter & formatter)346 void NumberFormat::InitUnitProperties(icu::number::UnlocalizedNumberFormatter &formatter)
347 {
348     if (styleString.empty() || styleString.compare("unit") != 0) {
349         return;
350     }
351     bool foundUnit = false;
352     for (icu::MeasureUnit curUnit : unitArray) {
353         if (!strcmp(curUnit.getSubtype(), unit.c_str())) {
354             formatter = formatter.unit(curUnit);
355             foundUnit = true;
356             unitType = curUnit.getType();
357         }
358     }
359     if (!foundUnit && fromArkTs) {
360         SetPerUnit(formatter);
361     }
362 
363     auto iter = measurementSystem.find(measurement);
364     if (iter != measurementSystem.end()) {
365         unitMeasSys = iter->second;
366     }
367 
368     formatter = formatter.unitWidth(unitDisplay);
369     formatter = formatter.precision(icu::number::Precision::maxFraction(DEFAULT_FRACTION_DIGITS));
370 }
371 
SetPerUnit(icu::number::UnlocalizedNumberFormatter & formatter)372 void NumberFormat::SetPerUnit(icu::number::UnlocalizedNumberFormatter &formatter)
373 {
374     icu::MeasureUnit icuUnit;
375     icu::MeasureUnit icuPerUnit;
376     if (!IsWellFormedUnitIdentifier(icuUnit, icuPerUnit)) {
377         HILOG_ERROR_I18N("NumberFormat::SetPerUnit: Get unit failed");
378         return;
379     }
380     icu::MeasureUnit emptyUnit = icu::MeasureUnit();
381     if (icuUnit != emptyUnit) {
382         formatter = formatter.unit(icuUnit);
383     }
384     if (icuPerUnit != emptyUnit) {
385         formatter = formatter.perUnit(icuPerUnit);
386     }
387 }
388 
InitDigitsProperties(icu::number::UnlocalizedNumberFormatter & formatter)389 void NumberFormat::InitDigitsProperties(icu::number::UnlocalizedNumberFormatter &formatter)
390 {
391     int32_t status = 0;
392     if (!maximumSignificantDigits.empty() || !minimumSignificantDigits.empty()) {
393         int32_t maxSignificantDigits = ConvertString2Int(maximumSignificantDigits, status);
394         if (status == 0) {
395             formatter = formatter.precision(icu::number::Precision::maxSignificantDigits(maxSignificantDigits));
396         }
397 
398         status = 0;
399         int32_t minSignificantDigits = ConvertString2Int(minimumSignificantDigits, status);
400         if (status == 0) {
401             formatter = formatter.precision(icu::number::Precision::minSignificantDigits(minSignificantDigits));
402         }
403     } else {
404         int32_t minIntegerDigits = ConvertString2Int(minimumIntegerDigits, status);
405         if (status == 0 && minIntegerDigits > 1) {
406             formatter = formatter.integerWidth(icu::number::IntegerWidth::zeroFillTo(minIntegerDigits));
407         }
408 
409         int32_t minFdStatus = 0;
410         int32_t minFractionDigits = ConvertString2Int(minimumFractionDigits, minFdStatus);
411         int32_t maxFdStatus = 0;
412         int32_t maxFractionDigits = ConvertString2Int(maximumFractionDigits, maxFdStatus);
413         if (minFdStatus == 0 || maxFdStatus == 0) {
414             isSetFraction = true;
415         }
416         if (minFdStatus == 0 && maxFdStatus != 0) {
417             formatter = formatter.precision(icu::number::Precision::minFraction(minFractionDigits));
418         } else if (minFdStatus != 0 && maxFdStatus == 0) {
419             formatter = formatter.precision(icu::number::Precision::maxFraction(maxFractionDigits));
420         } else if (minFdStatus == 0 && maxFdStatus == 0) {
421             formatter =
422                 formatter.precision(icu::number::Precision::minMaxFraction(minFractionDigits, maxFractionDigits));
423         }
424     }
425     SetRoundingProperties(formatter);
426     HandleRoundingPriority(formatter);
427 }
428 
SetRoundingProperties(icu::number::UnlocalizedNumberFormatter & formatter)429 void NumberFormat::SetRoundingProperties(icu::number::UnlocalizedNumberFormatter &formatter)
430 {
431     if (roundingIncrement != 1) {
432         int32_t maxFractionDigits = GetMaximumFractionDigitsValue();
433         double increment = pow(POW_BASE_NUMBER, -1.0 * maxFractionDigits) * roundingIncrement;
434         formatter = formatter.precision(icu::number::Precision::increment(increment));
435     }
436     if (!roundingModeStr.empty()) {
437         formatter = formatter.roundingMode(roundingMode);
438     }
439 }
440 
HandleRoundingPriority(icu::number::UnlocalizedNumberFormatter & formatter)441 void NumberFormat::HandleRoundingPriority(icu::number::UnlocalizedNumberFormatter &formatter)
442 {
443     if (roundingPriorityStr.empty()) {
444         return;
445     }
446     int32_t minFractionDigits = GetMinimumFractionDigitsValue();
447     int32_t maxFractionDigits = GetMaximumFractionDigitsValue();
448     int32_t maxSigDigits = GetMaximumSignificantDigitsIntValue();
449     int32_t minSigDigits = GetMinimumSignificantDigitsIntValue();
450     auto precision = icu::number::Precision::minMaxFraction(minFractionDigits, maxFractionDigits)
451         .withSignificantDigits(minSigDigits, maxSigDigits, roundingPriority);
452     formatter = formatter.precision(precision);
453 }
454 
GetMinimumSignificantDigitsIntValue()455 int32_t NumberFormat::GetMinimumSignificantDigitsIntValue()
456 {
457     int32_t minSignifDigits = 1;
458     if (!minimumSignificantDigits.empty()) {
459         int32_t status = 0;
460         int32_t minSignDigits = ConvertString2Int(minimumSignificantDigits, status);
461         minSignifDigits = (status == 0) ? minSignDigits : minSignifDigits;
462     }
463     return minSignifDigits;
464 }
465 
GetMaximumSignificantDigitsIntValue()466 int32_t NumberFormat::GetMaximumSignificantDigitsIntValue()
467 {
468     int32_t maxSign = DEFAULT_MAX_SIGNIFICANT_DIGITS;
469     if (!maximumSignificantDigits.empty()) {
470         int32_t status = 0;
471         int32_t maxSignDigits = ConvertString2Int(maximumSignificantDigits, status);
472         maxSign = (status == 0) ? maxSignDigits : maxSign;
473     }
474     return maxSign;
475 }
476 
GetMaximumFractionDigitsValue()477 int32_t NumberFormat::GetMaximumFractionDigitsValue()
478 {
479     int32_t maxFraction = DEFAULT_FRACTION_DIGITS;
480     if (!maximumFractionDigits.empty()) {
481         int32_t status = 0;
482         int32_t maxFractionDigits = ConvertString2Int(maximumFractionDigits, status);
483         maxFraction = (status == 0) ? maxFractionDigits : maxFraction;
484     }
485     return maxFraction;
486 }
487 
GetMinimumFractionDigitsValue()488 int32_t NumberFormat::GetMinimumFractionDigitsValue()
489 {
490     int32_t minFraction = 0;
491     if (!minimumFractionDigits.empty()) {
492         int32_t status = 0;
493         int32_t minFractionDigits = ConvertString2Int(minimumFractionDigits, status);
494         minFraction = (status == 0) ? minFractionDigits : minFraction;
495     }
496     return minFraction;
497 }
498 
ParseConfigs(std::map<std::string,std::string> & configs)499 void NumberFormat::ParseConfigs(std::map<std::string, std::string> &configs)
500 {
501     if (configs.count("signDisplay") > 0) {
502         signDisplayString = configs["signDisplay"];
503     }
504     if (signAutoStyle.count(signDisplayString) > 0) {
505         signDisplay = signAutoStyle[signDisplayString];
506     }
507     if (configs.count("style") > 0) {
508         styleString = configs["style"];
509     }
510     if (styleString == "unit" && configs.count("unit") > 0) {
511         unit = configs["unit"];
512         if (configs.count("unitDisplay") > 0) {
513             unitDisplayString = configs["unitDisplay"];
514             if (unitStyle.count(unitDisplayString) > 0) {
515                 unitDisplay = unitStyle[unitDisplayString];
516             }
517         }
518         if (configs.count("unitUsage") > 0) {
519             unitUsage = configs["unitUsage"];
520         }
521     }
522     if (styleString == "currency" && configs.count("currency") > 0) {
523         currency = GetCurrencyFromConfig(configs["currency"]);
524         if (configs.count("currencySign") > 0) {
525             currencySign = configs["currencySign"];
526         }
527         if (currencySign.compare("accounting") == 0 && signAccountingStyle.count(signDisplayString) > 0) {
528             signDisplay = signAccountingStyle[signDisplayString];
529         }
530         if (configs.count("currencyDisplay") > 0 && currencyStyle.count(configs["currencyDisplay"]) > 0) {
531             currencyDisplayString = configs["currencyDisplay"];
532             currencyDisplay = currencyStyle[currencyDisplayString];
533         }
534     }
535     ParseDigitsConfigs(configs);
536     ParseRoundingConfigs(configs);
537 }
538 
ParseDigitsConfigs(std::map<std::string,std::string> & configs)539 void NumberFormat::ParseDigitsConfigs(std::map<std::string, std::string> &configs)
540 {
541     if (configs.count("notation") > 0) {
542         notationString = configs["notation"];
543         if (notationString == "scientific") {
544             notation = icu::number::Notation::scientific();
545         } else if (notationString == "engineering") {
546             notation = icu::number::Notation::engineering();
547         }
548         if (notationString == "compact") {
549             if (configs.count("compactDisplay") > 0) {
550                 compactDisplay = configs["compactDisplay"];
551             }
552             if (compactDisplay == "long") {
553                 notation = icu::number::Notation::compactLong();
554             } else {
555                 notation = icu::number::Notation::compactShort();
556             }
557         }
558     }
559     if (configs.count("minimumIntegerDigits") > 0) {
560         minimumIntegerDigits = configs["minimumIntegerDigits"];
561     }
562     if (configs.count("minimumFractionDigits") > 0) {
563         minimumFractionDigits = configs["minimumFractionDigits"];
564     }
565     if (configs.count("maximumFractionDigits") > 0) {
566         maximumFractionDigits = configs["maximumFractionDigits"];
567     }
568     if (configs.count("minimumSignificantDigits") > 0) {
569         minimumSignificantDigits = configs["minimumSignificantDigits"];
570     }
571     if (configs.count("maximumSignificantDigits") > 0) {
572         maximumSignificantDigits = configs["maximumSignificantDigits"];
573     }
574     if (configs.count("numberingSystem") > 0) {
575         numberingSystem = configs["numberingSystem"];
576     }
577     if (configs.count("useGrouping") > 0) {
578         useGrouping = configs["useGrouping"];
579     }
580     if (configs.count("localeMatcher") > 0) {
581         localeMatcher = configs["localeMatcher"];
582     }
583 }
584 
ParseRoundingConfigs(std::map<std::string,std::string> & configs)585 void NumberFormat::ParseRoundingConfigs(std::map<std::string, std::string> &configs)
586 {
587     if (configs.count("roundingMode") > 0) {
588         std::string tempRoundingModeStr = configs["roundingMode"];
589         auto iter = roundingModeStyle.find(tempRoundingModeStr);
590         if (iter != roundingModeStyle.end()) {
591             roundingMode = iter->second;
592             roundingModeStr = tempRoundingModeStr;
593         }
594     }
595     if (configs.count("roundingPriority") > 0) {
596         std::string tempRoundingPriorityStr = configs["roundingPriority"];
597         auto iter = roundingPriorityStyle.find(tempRoundingPriorityStr);
598         if (iter != roundingPriorityStyle.end()) {
599             roundingPriorityStr = tempRoundingPriorityStr;
600             roundingPriority = iter->second;
601         }
602     }
603     if (configs.count("roundingIncrement") > 0) {
604         std::string increment = configs["roundingIncrement"];
605         int32_t status = 0;
606         int32_t incrementNum = ConvertString2Int(increment, status);
607         if (status != 0) {
608             HILOG_ERROR_I18N("NumberFormat::ParseRoundingConfigs: Convert string to int failed.");
609             return;
610         }
611         auto iter = std::find(roundingIncrementList.begin(), roundingIncrementList.end(),
612             static_cast<size_t>(incrementNum));
613         if (iter != roundingIncrementList.end()) {
614             roundingIncrement = *iter;
615         }
616     }
617 }
618 
ParseExtParam(const std::string & localeTag)619 void NumberFormat::ParseExtParam(const std::string& localeTag)
620 {
621     std::pair<std::string, std::string> numberPattern = LocaleConfig::GetNumberPatternFromLocale(localeTag);
622     if (numberPattern.second.empty()) {
623         return;
624     }
625     groupingSymbol = numberPattern.first;
626     decimalSymbol = numberPattern.second;
627     preferredTemperature =
628         LocaleConfig::GetTemperatureName(LocaleConfig::GetTemperatureTypeFromLocale(localeTag));
629     effectiveLocale = LocaleConfig::RemoveCustExtParam(localeTag);
630     if (!numberingSystem.empty()) {
631         effectiveLocale = LocaleConfig::ModifyExtParam(effectiveLocale, "nu", numberingSystem, "-u-");
632     }
633     measurement = LocaleConfig::GetMeasurementFromLocale(localeTag);
634 }
635 
SetUnit(std::string & preferredUnit)636 void NumberFormat::SetUnit(std::string &preferredUnit)
637 {
638     if (preferredUnit.empty()) {
639         return;
640     }
641     for (icu::MeasureUnit curUnit : unitArray) {
642         if (!strcmp(curUnit.getSubtype(), preferredUnit.c_str())) {
643             numberFormat = numberFormat.unit(curUnit);
644             styleFormatter = styleFormatter.unit(curUnit);
645         }
646     }
647 }
648 
Format(double number)649 std::string NumberFormat::Format(double number)
650 {
651     std::string result;
652     UErrorCode status = U_ZERO_ERROR;
653     icu::UnicodeString formatResult;
654     if (IsRelativeTimeFormat(number)) {
655         icu::FormattedRelativeDateTime formattedTime = FormatToFormattedRelativeDateTime(number);
656         formatResult = formattedTime.toString(status);
657     } else {
658         icu::number::FormattedNumber formattedNumber = FormatToFormattedNumber(number);
659         formatResult = formattedNumber.toString(status);
660     }
661     if (U_FAILURE(status)) {
662         result = "";
663     } else {
664         formatResult.toUTF8String(result);
665     }
666     return PseudoLocalizationProcessor(result);
667 }
668 
FormatBigInt(const std::string & number)669 std::string NumberFormat::FormatBigInt(const std::string &number)
670 {
671     std::string result;
672     icu::number::FormattedNumber formattedNumber = FormatDecimalToFormattedNumber(number);
673     UErrorCode status = U_ZERO_ERROR;
674     icu::UnicodeString formatResult = formattedNumber.toString(status);
675     if (U_SUCCESS(status)) {
676         formatResult.toUTF8String(result);
677     }
678     return PseudoLocalizationProcessor(result);
679 }
680 
FormatToParts(std::vector<std::vector<std::string>> & result)681 void NumberFormat::FormatToParts(std::vector<std::vector<std::string>> &result)
682 {
683     double number = uprv_getNaN();
684     icu::number::FormattedNumber formattedNumber = FormatToFormattedNumber(number);
685     FormattedNumberParts(formattedNumber, result, "nan", number);
686 }
687 
FormatBigIntToParts(std::string & number,std::vector<std::vector<std::string>> & result)688 void NumberFormat::FormatBigIntToParts(std::string &number, std::vector<std::vector<std::string>> &result)
689 {
690     icu::number::FormattedNumber formattedNumber = FormatDecimalToFormattedNumber(number);
691     double numDouble = GetBigIntFieldType(number);
692     FormattedNumberParts(formattedNumber, result, "bigint", numDouble);
693 }
694 
GetBigIntFieldType(const std::string & bigIntStr)695 double NumberFormat::GetBigIntFieldType(const std::string &bigIntStr)
696 {
697     double numDouble = 0;
698     if (!bigIntStr.empty() && bigIntStr.at(0) == '-') {
699         numDouble = -1.0; // -1 just means number is negative
700     }
701     return numDouble;
702 }
703 
FormatToParts(double number,std::vector<std::vector<std::string>> & result)704 void NumberFormat::FormatToParts(double number, std::vector<std::vector<std::string>> &result)
705 {
706     std::string finalUnit = unit;
707     if (IsRelativeTimeFormat(number, finalUnit)) {
708         RelativeDateTimeFormatToParts(number, finalUnit, result);
709         return;
710     }
711     icu::number::FormattedNumber formattedNumber = FormatToFormattedNumber(number);
712     FormattedNumberParts(formattedNumber, result, "number", number);
713 }
714 
FormattedNumberParts(icu::number::FormattedNumber & formattedNumber,std::vector<std::vector<std::string>> & result,const std::string & napiType,const double & number)715 void NumberFormat::FormattedNumberParts(icu::number::FormattedNumber &formattedNumber,
716     std::vector<std::vector<std::string>> &result, const std::string &napiType,
717     const double &number)
718 {
719     UErrorCode status = U_ZERO_ERROR;
720     icu::UnicodeString formatResult = formattedNumber.toString(status);
721     if (U_FAILURE(status)) {
722         HILOG_ERROR_I18N("NumberFormat::FormatToParts: UnicodeString toString failed.");
723         return;
724     }
725     FindAllFormatParts(formattedNumber, result, number, napiType, formatResult);
726 }
727 
FindAllFormatParts(icu::FormattedValue & formattedNumber,std::vector<std::vector<std::string>> & result,double number,const std::string & napiType,icu::UnicodeString & formatResult)728 void NumberFormat::FindAllFormatParts(icu::FormattedValue &formattedNumber,
729     std::vector<std::vector<std::string>> &result, double number,
730     const std::string &napiType, icu::UnicodeString &formatResult)
731 {
732     icu::ConstrainedFieldPosition cfpo;
733     int previousLimit = 0;
734     bool lastFieldGroup = false;
735     int groupLeapLength = 0;
736     UErrorCode status = U_ZERO_ERROR;
737     struct FormatPartParam param = {previousLimit, lastFieldGroup, groupLeapLength, number, napiType};
738     while (formattedNumber.nextPosition(cfpo, status)) {
739         if (U_FAILURE(status)) {
740             HILOG_ERROR_I18N("NumberFormat::FindAllFormatParts: Get next position failed.");
741             result.clear();
742             return;
743         }
744         SetEveryFormatPartItem(cfpo, formatResult, result, param);
745     }
746     if (formatResult.length() > param.previousLimit) {
747         std::string typeString = "literal";
748         AddFormatParts(typeString, result, formatResult, param.previousLimit, formatResult.length());
749     }
750 }
751 
FindAllFormatParts(icu::FormattedValue & formattedNumber,std::vector<std::vector<std::string>> & result,const double & first,const double & second,icu::UnicodeString & formatResult)752 void NumberFormat::FindAllFormatParts(icu::FormattedValue &formattedNumber,
753     std::vector<std::vector<std::string>> &result, const double &first,
754     const double &second, icu::UnicodeString &formatResult)
755 {
756     icu::ConstrainedFieldPosition cfpo;
757     int previousLimit = 0;
758     bool lastFieldGroup = false;
759     int groupLeapLength = 0;
760     size_t rangeSpanCount = 0;
761     struct FormatPartParam param = {previousLimit, lastFieldGroup, groupLeapLength, first, "number"};
762     UErrorCode status = U_ZERO_ERROR;
763     while (formattedNumber.nextPosition(cfpo, status)) {
764         if (U_FAILURE(status)) {
765             HILOG_ERROR_I18N("NumberFormat::FindAllFormatParts: Get next position failed.");
766             result.clear();
767             return;
768         }
769         if (static_cast<UFieldCategory>(cfpo.getCategory()) == UFIELD_CATEGORY_NUMBER_RANGE_SPAN) {
770             ++rangeSpanCount;
771         }
772         if (rangeSpanCount > 1) {
773             param.number = second;
774         }
775         SetEveryFormatPartItem(cfpo, formatResult, result, param);
776     }
777     if (formatResult.length() > param.previousLimit) {
778         std::string typeString = "literal";
779         AddFormatParts(typeString, result, formatResult, param.previousLimit, formatResult.length());
780     }
781 }
782 
SetEveryFormatPartItem(icu::ConstrainedFieldPosition & cfpo,icu::UnicodeString & formatResult,std::vector<std::vector<std::string>> & result,FormatPartParam & param)783 void NumberFormat::SetEveryFormatPartItem(icu::ConstrainedFieldPosition &cfpo, icu::UnicodeString &formatResult,
784     std::vector<std::vector<std::string>> &result, FormatPartParam &param)
785 {
786     int32_t fieldId = cfpo.getField();
787     int32_t start = cfpo.getStart();
788     int32_t limit = cfpo.getLimit();
789     std::string typeString = "literal";
790     if (static_cast<UFieldCategory>(cfpo.getCategory()) == UFIELD_CATEGORY_NUMBER_RANGE_SPAN) {
791         if (param.previousLimit < start) {
792             AddFormatParts(typeString, result, formatResult, param.previousLimit, start);
793             param.previousLimit = start;
794         }
795         return;
796     }
797     if (static_cast<UNumberFormatFields>(fieldId) == UNUM_GROUPING_SEPARATOR_FIELD) {
798         typeString = "integer";
799         AddFormatParts(typeString, result, formatResult, param.previousLimit, start);
800         {
801             typeString = FormatUtils::GetNumberFieldType(param.napiType, fieldId, param.number);
802             AddFormatParts(typeString, result, formatResult, start, limit);
803         }
804         param.lastFieldGroup = true;
805         param.groupLeapLength = start - param.previousLimit + 1;
806         param.previousLimit = limit;
807         return;
808     } else if (start > param.previousLimit) {
809         AddFormatParts(typeString, result, formatResult, param.previousLimit, start);
810     }
811     if (param.lastFieldGroup) {
812         start = start + param.groupLeapLength;
813         param.lastFieldGroup = false;
814     }
815     if (styleString.compare("unit") == 0 && static_cast<UNumberFormatFields>(fieldId) == UNUM_PERCENT_FIELD) {
816         typeString = "unit";
817     } else {
818         typeString = FormatUtils::GetNumberFieldType(param.napiType, fieldId, param.number);
819     }
820     if (start < param.previousLimit && param.previousLimit < limit) {
821         AddFormatParts(typeString, result, formatResult, param.previousLimit, limit);
822     } else {
823         AddFormatParts(typeString, result, formatResult, start, limit);
824     }
825     param.previousLimit = limit;
826 }
827 
AddFormatParts(std::string typeString,std::vector<std::vector<std::string>> & result,icu::UnicodeString & formatResult,int32_t start,int32_t end)828 void NumberFormat::AddFormatParts(std::string typeString, std::vector<std::vector<std::string>> &result,
829     icu::UnicodeString &formatResult, int32_t start, int32_t end)
830 {
831     std::string value = GetSubString(formatResult, start, end);
832     std::vector<std::string> info;
833     info.push_back(typeString);
834     info.push_back(value);
835     result.push_back(info);
836 }
837 
GetSubString(icu::UnicodeString & formatResult,int32_t start,int32_t end)838 std::string NumberFormat::GetSubString(icu::UnicodeString &formatResult, int32_t start, int32_t end)
839 {
840     icu::UnicodeString substring = formatResult.tempSubStringBetween(start, end);
841     std::string val;
842     substring.toUTF8String(val);
843     return val;
844 }
845 
RelativeDateTimeFormatToParts(double number,std::string & finalUnit,std::vector<std::vector<std::string>> & result)846 void NumberFormat::RelativeDateTimeFormatToParts(double number, std::string &finalUnit,
847     std::vector<std::vector<std::string>> &result)
848 {
849     if (!createSuccess) {
850         return;
851     }
852     double finalNumber = number;
853     if (relativeTimeFormat == nullptr) {
854         return;
855     }
856     relativeTimeFormat->FormatToParts(finalNumber, finalUnit, result);
857 }
858 
IsRelativeTimeFormat(double number)859 bool NumberFormat::IsRelativeTimeFormat(double number)
860 {
861     double finalNumber = number;
862     std::string finalUnit = unit;
863     return IsRelativeTimeFormat(finalNumber, finalUnit);
864 }
865 
IsRelativeTimeFormat(double number,std::string & unitForConvert)866 bool NumberFormat::IsRelativeTimeFormat(double number, std::string &unitForConvert)
867 {
868     double finalNumber = number;
869     if (unitUsage.compare("elapsed-time-second") == 0 && ConvertDate(finalNumber, unitForConvert) &&
870         relativeTimeFormat != nullptr) {
871         return true;
872     }
873     return false;
874 }
875 
FormatDecimalToFormattedNumber(const std::string & number)876 icu::number::FormattedNumber NumberFormat::FormatDecimalToFormattedNumber(const std::string &number)
877 {
878     if (!createSuccess) {
879         return {};
880     }
881     UErrorCode status = U_ZERO_ERROR;
882     icu::number::FormattedNumber formattedNumber =
883         numberFormat.formatDecimal(icu::StringPiece(number), status);
884     if (U_FAILURE(status)) {
885         HILOG_ERROR_I18N("FormatDecimalToFormattedNumber: format %{public}s failed.", number.c_str());
886         return {};
887     }
888     return formattedNumber;
889 }
890 
FormatToFormattedNumber(double number)891 icu::number::FormattedNumber NumberFormat::FormatToFormattedNumber(double number)
892 {
893     if (!createSuccess) {
894         return {};
895     }
896     double temp = 0;
897     NumberFormat::DealWithUnitUsage(false, number, temp);
898     UErrorCode icuStatus = U_ZERO_ERROR;
899     icu::number::FormattedNumber formattedNumber = numberFormat.formatDouble(number, icuStatus);
900     if (U_FAILURE(icuStatus)) {
901         return {};
902     }
903     return formattedNumber;
904 }
905 
FormatToFormattedRelativeDateTime(double number)906 icu::FormattedRelativeDateTime NumberFormat::FormatToFormattedRelativeDateTime(double number)
907 {
908     if (!createSuccess) {
909         return {};
910     }
911 
912     double finalNumber = number;
913     std::string finalUnit = unit;
914     if (unitUsage.compare("elapsed-time-second") == 0 && ConvertDate(finalNumber, finalUnit) &&
915         relativeTimeFormat != nullptr) {
916         return relativeTimeFormat->FormatToFormattedValue(finalNumber, finalUnit);
917     }
918     return {};
919 }
920 
FormatRange(double start,double end)921 std::string NumberFormat::FormatRange(double start, double end)
922 {
923     if (!createSuccess) {
924         HILOG_ERROR_I18N("FormatRange: init numberRangeFormat failed.");
925         return PseudoLocalizationProcessor("");
926     }
927     if (end < start) {
928         HILOG_ERROR_I18N("FormatRange: parameter:end less then parameter:start");
929         return PseudoLocalizationProcessor("");
930     }
931     NumberFormat::DealWithUnitUsage(true, start, end);
932     icu::number::LocalizedNumberRangeFormatter tempNumberRangeFormat = icu::number::NumberRangeFormatter::with()
933         .numberFormatterBoth(styleFormatter)
934         .locale(locale);
935     UErrorCode status = U_ZERO_ERROR;
936     icu::number::FormattedNumberRange numberRange = tempNumberRangeFormat.formatFormattableRange(start, end, status);
937     if (U_FAILURE(status)) {
938         HILOG_ERROR_I18N("FormatRange: formatFormattableRange failed.");
939         return PseudoLocalizationProcessor("");
940     }
941     icu::UnicodeString res = numberRange.toString(status);
942     if (U_FAILURE(status)) {
943         HILOG_ERROR_I18N("FormatRange: icu::UnicodeString.toString() failed.");
944         return PseudoLocalizationProcessor("");
945     }
946     std::string result;
947     res.toUTF8String(result);
948     return PseudoLocalizationProcessor(result);
949 }
950 
FormatJsRange(double first,double second)951 std::string NumberFormat::FormatJsRange(double first, double second)
952 {
953     if (!createSuccess) {
954         HILOG_ERROR_I18N("FormatRange: init numberRangeFormat failed.");
955         return PseudoLocalizationProcessor("");
956     }
957     icu::number::LocalizedNumberRangeFormatter tempNumberRangeFormat = icu::number::NumberRangeFormatter::with()
958         .numberFormatterBoth(styleFormatter)
959         .locale(locale);
960     UErrorCode status = U_ZERO_ERROR;
961     icu::number::FormattedNumberRange numberRange =
962         tempNumberRangeFormat.formatFormattableRange(first, second, status);
963     if (U_FAILURE(status)) {
964         HILOG_ERROR_I18N("FormatRange: formatFormattableRange failed.");
965         return PseudoLocalizationProcessor("");
966     }
967     icu::UnicodeString unicodeStr = numberRange.toString(status);
968     if (U_FAILURE(status)) {
969         HILOG_ERROR_I18N("FormatRange: icu::UnicodeString.toString() failed.");
970         return PseudoLocalizationProcessor("");
971     }
972     std::string result;
973     unicodeStr.toUTF8String(result);
974     return PseudoLocalizationProcessor(result);
975 }
976 
FormatRangeToParts(const double & first,const double & second,std::vector<std::vector<std::string>> & result)977 void NumberFormat::FormatRangeToParts(const double &first, const double &second,
978     std::vector<std::vector<std::string>> &result)
979 {
980     FormatableRangeToParts(first, second, result);
981 }
982 
FormatableRangeToParts(double first,double second,std::vector<std::vector<std::string>> & result)983 void NumberFormat::FormatableRangeToParts(double first, double second,
984     std::vector<std::vector<std::string>> &result)
985 {
986     if (!createSuccess) {
987         HILOG_ERROR_I18N("NumberFormat::FormatableRangeToParts: init numberRangeFormat failed.");
988         return;
989     }
990     icu::number::LocalizedNumberRangeFormatter tempNumberRangeFormat = icu::number::NumberRangeFormatter::with()
991         .numberFormatterBoth(styleFormatter)
992         .locale(locale);
993     UErrorCode status = U_ZERO_ERROR;
994     icu::number::FormattedNumberRange numberRange =
995         tempNumberRangeFormat.formatFormattableRange(first, second, status);
996     if (U_FAILURE(status)) {
997         HILOG_ERROR_I18N("NumberFormat::FormatableRangeToParts: formatFormattableRange failed.");
998         return;
999     }
1000     icu::UnicodeString res = numberRange.toString(status);
1001     if (U_FAILURE(status)) {
1002         HILOG_ERROR_I18N("NumberFormat::FormatableRangeToParts: icu::UnicodeString.toString() failed.");
1003         return;
1004     }
1005     FindAllFormatParts(numberRange, result, first, second, res);
1006 }
1007 
GetResolvedOptions(std::map<std::string,std::string> & map,bool setDefault)1008 void NumberFormat::GetResolvedOptions(std::map<std::string, std::string> &map, bool setDefault)
1009 {
1010     map.insert(std::make_pair("locale", localeBaseName));
1011     if (!styleString.empty()) {
1012         map.insert(std::make_pair("style", styleString));
1013     } else {
1014         if (setDefault) {
1015             map.insert(std::make_pair("style", "decimal"));
1016         }
1017     }
1018     if (!currency.empty()) {
1019         map.insert(std::make_pair("currency", currency));
1020     }
1021     if (!currencySign.empty()) {
1022         map.insert(std::make_pair("currencySign", currencySign));
1023     } else if (setDefault) {
1024         map.insert(std::make_pair("currencySign", "standard"));
1025     }
1026     if (!currencyDisplayString.empty()) {
1027         map.insert(std::make_pair("currencyDisplay", currencyDisplayString));
1028     } else if (setDefault) {
1029         map.insert(std::make_pair("currencyDisplay", "symbol"));
1030     }
1031     if (!signDisplayString.empty()) {
1032         map.insert(std::make_pair("signDisplay", signDisplayString));
1033     } else if (setDefault) {
1034         map.insert(std::make_pair("signDisplay", "auto"));
1035     }
1036     if (!compactDisplay.empty()) {
1037         map.insert(std::make_pair("compactDisplay", compactDisplay));
1038     }
1039     if (!unitDisplayString.empty()) {
1040         map.insert(std::make_pair("unitDisplay", unitDisplayString));
1041     }
1042     if (!unitUsage.empty()) {
1043         map.insert(std::make_pair("unitUsage", unitUsage));
1044     }
1045     if (!unit.empty()) {
1046         map.insert(std::make_pair("unit", unit));
1047     }
1048     GetDigitsResolvedOptions(map, setDefault);
1049     GetDigitsResolvedOptionsExt(map, setDefault);
1050 }
1051 
SupportedLocalesOf(const std::vector<std::string> & requestLocales,const std::map<std::string,std::string> & configs,I18nErrorCode & status)1052 std::vector<std::string> NumberFormat::SupportedLocalesOf(const std::vector<std::string> &requestLocales,
1053     const std::map<std::string, std::string> &configs, I18nErrorCode &status)
1054 {
1055     return LocaleHelper::SupportedLocalesOf(requestLocales, configs, status);
1056 }
1057 
GetDigitsResolvedOptions(std::map<std::string,std::string> & map,bool setDefault)1058 void NumberFormat::GetDigitsResolvedOptions(std::map<std::string, std::string> &map, bool setDefault)
1059 {
1060     if (!numberingSystem.empty()) {
1061         map.insert(std::make_pair("numberingSystem", numberingSystem));
1062     } else if (!(localeInfo->GetNumberingSystem()).empty()) {
1063         map.insert(std::make_pair("numberingSystem", localeInfo->GetNumberingSystem()));
1064     } else {
1065         UErrorCode status = U_ZERO_ERROR;
1066         auto numSys = std::unique_ptr<icu::NumberingSystem>(icu::NumberingSystem::createInstance(locale, status));
1067         if (U_SUCCESS(status)) {
1068             map.insert(std::make_pair("numberingSystem", numSys->getName()));
1069         }
1070     }
1071     if (!useGrouping.empty()) {
1072         map.insert(std::make_pair("useGrouping", useGrouping));
1073     } else if (setDefault) {
1074         map.insert(std::make_pair("useGrouping", "true"));
1075     }
1076     if (!minimumIntegerDigits.empty()) {
1077         map.insert(std::make_pair("minimumIntegerDigits", minimumIntegerDigits));
1078     } else if (setDefault) {
1079         map.insert(std::make_pair("minimumIntegerDigits", "1"));
1080     }
1081     if (!minimumFractionDigits.empty()) {
1082         map.insert(std::make_pair("minimumFractionDigits", minimumFractionDigits));
1083     } else if (setDefault) {
1084         GetMinimumFractionDigitsOption(map);
1085     }
1086     if (!maximumFractionDigits.empty()) {
1087         map.insert(std::make_pair("maximumFractionDigits", maximumFractionDigits));
1088     } else if (setDefault) {
1089         GetMaximumFractionDigitsOption(map);
1090     }
1091     if (!minimumSignificantDigits.empty()) {
1092         map.insert(std::make_pair("minimumSignificantDigits", minimumSignificantDigits));
1093     }
1094     if (!maximumSignificantDigits.empty()) {
1095         map.insert(std::make_pair("maximumSignificantDigits", maximumSignificantDigits));
1096     }
1097 }
1098 
GetDigitsResolvedOptionsExt(std::map<std::string,std::string> & map,bool setDefault)1099 void NumberFormat::GetDigitsResolvedOptionsExt(std::map<std::string, std::string> &map, bool setDefault)
1100 {
1101     if (!localeMatcher.empty()) {
1102         map.insert(std::make_pair("localeMatcher", localeMatcher));
1103     }
1104     if (!notationString.empty()) {
1105         map.insert(std::make_pair("notation", notationString));
1106     } else if (setDefault) {
1107         map.insert(std::make_pair("notation", "standard"));
1108     }
1109     if (!roundingModeStr.empty()) {
1110         map.insert(std::make_pair("roundingMode", roundingModeStr));
1111     }
1112     if (!roundingPriorityStr.empty()) {
1113         map.insert(std::make_pair("roundingPriority", roundingPriorityStr));
1114     }
1115     if (roundingIncrement != 1) {
1116         map.insert(std::make_pair("roundingIncrement", std::to_string(roundingIncrement)));
1117     }
1118 }
1119 
GetMinimumFractionDigitsOption(std::map<std::string,std::string> & map)1120 void NumberFormat::GetMinimumFractionDigitsOption(std::map<std::string, std::string> &map)
1121 {
1122     std::string style = "decimal";
1123     if (map.find("style") != map.end()) {
1124         style = map["style"];
1125     }
1126     if (style == "decimal" || style == "percent") {
1127         map.insert(std::make_pair("minimumFractionDigits", "0"));
1128     } else if (style == "currency") {
1129         int fraction = GetCurrencyFractionDigits(map);
1130         map.insert(std::make_pair("minimumFractionDigits", std::to_string(fraction)));
1131     }
1132 }
1133 
GetMaximumFractionDigitsOption(std::map<std::string,std::string> & map)1134 void NumberFormat::GetMaximumFractionDigitsOption(std::map<std::string, std::string> &map)
1135 {
1136     std::string style = "decimal";
1137     if (map.find("style") != map.end()) {
1138         style = map["style"];
1139     }
1140     if (style == "decimal") {
1141         map.insert(std::make_pair("maximumFractionDigits", "3"));
1142     } else if (style == "percent") {
1143         map.insert(std::make_pair("maximumFractionDigits", "0"));
1144     } else if (style == "currency") {
1145         int fraction = GetCurrencyFractionDigits(map);
1146         map.insert(std::make_pair("maximumFractionDigits", std::to_string(fraction)));
1147     }
1148 }
1149 
GetCurrencyFractionDigits(std::map<std::string,std::string> & map)1150 int NumberFormat::GetCurrencyFractionDigits(std::map<std::string, std::string> &map)
1151 {
1152     int result = 2; // 2 is default value
1153     std::string currency;
1154     if (map.find("currency") != map.end()) {
1155         currency = map["currency"];
1156         currency = GetCurrencyFromConfig(currency);
1157     }
1158     if (defaultCurrencyFractionMap.find(currency) != defaultCurrencyFractionMap.end()) {
1159         result = defaultCurrencyFractionMap[currency];
1160     }
1161     return result;
1162 }
1163 
SetPrecisionWithByte(double number,const std::string & finalUnit)1164 void NumberFormat::SetPrecisionWithByte(double number, const std::string& finalUnit)
1165 {
1166     if (isSetFraction) {
1167         return;
1168     }
1169     int32_t FractionDigits = -1;
1170     // 100 is the threshold between different decimal
1171     if (finalUnit == "byte" || number >= 100) {
1172         FractionDigits = 0;
1173     } else if (number < 1) {
1174         // 2 is the number of significant digits in the decimal
1175         FractionDigits = 2;
1176     // 10 is the threshold between different decimal
1177     } else if (number < 10) {
1178         if (unitUsage == "size-shortfile-byte") {
1179             FractionDigits = 1;
1180         } else {
1181             // 2 is the number of significant digits in the decimal
1182             FractionDigits = 2;
1183         }
1184     } else {
1185         if (unitUsage == "size-shortfile-byte") {
1186             FractionDigits = 0;
1187         } else {
1188             // 2 is the number of significant digits in the decimal
1189             FractionDigits = 2;
1190         }
1191     }
1192     if (FractionDigits != -1) {
1193         numberFormat = numberFormat.precision(icu::number::Precision::minMaxFraction(FractionDigits, FractionDigits));
1194         styleFormatter =
1195             styleFormatter.precision(icu::number::Precision::minMaxFraction(FractionDigits, FractionDigits));
1196     }
1197 }
1198 
GetCurrency() const1199 std::string NumberFormat::GetCurrency() const
1200 {
1201     return currency;
1202 }
1203 
GetCurrencySign() const1204 std::string NumberFormat::GetCurrencySign() const
1205 {
1206     return currencySign;
1207 }
1208 
GetStyle() const1209 std::string NumberFormat::GetStyle() const
1210 {
1211     return styleString;
1212 }
1213 
GetNumberingSystem() const1214 std::string NumberFormat::GetNumberingSystem() const
1215 {
1216     return numberingSystem;
1217 }
1218 
GetUseGrouping() const1219 std::string NumberFormat::GetUseGrouping() const
1220 {
1221     return useGrouping;
1222 }
1223 
GetMinimumIntegerDigits() const1224 std::string NumberFormat::GetMinimumIntegerDigits() const
1225 {
1226     return minimumIntegerDigits;
1227 }
1228 
GetMinimumFractionDigits() const1229 std::string NumberFormat::GetMinimumFractionDigits() const
1230 {
1231     return minimumFractionDigits;
1232 }
1233 
GetMaximumFractionDigits() const1234 std::string NumberFormat::GetMaximumFractionDigits() const
1235 {
1236     return maximumFractionDigits;
1237 }
1238 
GetMinimumSignificantDigits() const1239 std::string NumberFormat::GetMinimumSignificantDigits() const
1240 {
1241     return minimumSignificantDigits;
1242 }
1243 
GetMaximumSignificantDigits() const1244 std::string NumberFormat::GetMaximumSignificantDigits() const
1245 {
1246     return maximumSignificantDigits;
1247 }
1248 
GetLocaleMatcher() const1249 std::string NumberFormat::GetLocaleMatcher() const
1250 {
1251     return localeMatcher;
1252 }
1253 
Init()1254 bool NumberFormat::Init()
1255 {
1256     SetHwIcuDirectory();
1257     return true;
1258 }
1259 
SetDefaultStyle()1260 void NumberFormat::SetDefaultStyle()
1261 {
1262     char value[LocaleConfig::CONFIG_LEN];
1263     int code = GetParameter(DEVICE_TYPE_NAME, "", value, LocaleConfig::CONFIG_LEN);
1264     if (code > 0) {
1265         std::string deviceType = value;
1266         if (defaultUnitStyle.find(deviceType) != defaultUnitStyle.end()) {
1267             unitDisplay = defaultUnitStyle[deviceType];
1268         }
1269         if (defaultCurrencyStyle.find(deviceType) != defaultCurrencyStyle.end()) {
1270             currencyDisplay = defaultCurrencyStyle[deviceType];
1271         }
1272     }
1273 }
1274 
ReadISO4217Datas()1275 bool NumberFormat::ReadISO4217Datas()
1276 {
1277     if (initISO4217) {
1278         return true;
1279     }
1280     std::lock_guard<std::mutex> readDataLock(numToCurrencyMutex);
1281     if (initISO4217) {
1282         return true;
1283     }
1284     UErrorCode status = U_ZERO_ERROR;
1285     const char *currentCurrency;
1286     UEnumeration *currencies = ucurr_openISOCurrencies(UCURR_ALL, &status);
1287     if (U_FAILURE(status)) {
1288         return false;
1289     }
1290 
1291     UChar code[CURRENCY_LEN + 1];  // +1 includes the NUL
1292     int32_t length = 0;
1293     while ((currentCurrency = uenum_next(currencies, &length, &status)) != NULL) {
1294         u_charsToUChars(currentCurrency, code, length + 1);  // +1 includes the NUL
1295         int32_t numCode = ucurr_getNumericCode(code);
1296         if (numCode == 0) {
1297             continue;
1298         }
1299         std::stringstream ss;
1300         ss << std::setw(CURRENCY_LEN) << std::setfill('0') << numCode; // fill with '0'
1301         numToCurrency.insert(std::make_pair<std::string, std::string>(ss.str(), currentCurrency));
1302     }
1303     uenum_close(currencies);
1304     initISO4217 = true;
1305     return !numToCurrency.empty();
1306 }
1307 
GetCurrencyFromConfig(const std::string & currency)1308 std::string NumberFormat::GetCurrencyFromConfig(const std::string& currency)
1309 {
1310     if (currency.size() != CURRENCY_LEN) {
1311         HILOG_ERROR_I18N("Invalid currency code : %{public}s", currency.c_str());
1312         return "";
1313     }
1314     bool isAlpha = true;
1315     for (auto c : currency) {
1316         isAlpha = std::isalpha(c);
1317         if (!isAlpha) {
1318             break;
1319         }
1320     }
1321     if (isAlpha) {
1322         return currency;
1323     }
1324     if (ReadISO4217Datas() && numToCurrency.find(currency) != numToCurrency.end()) {
1325         return numToCurrency[currency];
1326     }
1327     HILOG_ERROR_I18N("Invalid currency code : %{public}s", currency.c_str());
1328     return "";
1329 }
1330 
GetIcuDefaultLocale()1331 std::string NumberFormat::GetIcuDefaultLocale()
1332 {
1333     return "en-US";
1334 }
1335 
CheckNumberFormatOptions(std::map<std::string,std::string> & map,int32_t & code)1336 std::string NumberFormat::CheckNumberFormatOptions(std::map<std::string, std::string> &map, int32_t &code)
1337 {
1338     std::string message = CheckFormatOptions(map, code);
1339     if (!message.empty()) {
1340         return message;
1341     }
1342     std::vector<std::tuple<std::string, int, int>> vect = {
1343         {"minimumIntegerDigits", 1, 21}, // 21 is maximum of minimumIntegerDigits
1344         {"minimumFractionDigits", 0, 20}, // 20 is maximum of minimumFractionDigits
1345         {"maximumFractionDigits", 0, 20}, // 20 is maximum of maximumFractionDigits
1346         {"minimumSignificantDigits", 1, 21}, // 21 is maximum of minimumSignificantDigits
1347         {"maximumSignificantDigits", 1, 21}, // 21 is maximum of maximumSignificantDigits
1348     };
1349     for (auto iter = vect.begin(); iter != vect.end(); ++iter) {
1350         std::string optionName = std::get<0>(*iter);
1351         int min = std::get<1>(*iter); // 1 is item index
1352         int max = std::get<2>(*iter); // 2 is item index
1353         CheckNumberFormatOptionsExt(map, code, optionName, min, max);
1354         if (code != 0) {
1355             return "";
1356         }
1357     }
1358     return "";
1359 }
1360 
CheckFormatOptions(std::map<std::string,std::string> & map,int32_t & code)1361 std::string NumberFormat::CheckFormatOptions(std::map<std::string, std::string> &map, int32_t &code)
1362 {
1363     if (map.find("style") != map.end()) {
1364         std::string style = map["style"];
1365         if (style.compare("currency") == 0 && map.find("currency") == map.end()) {
1366             code = -1;
1367             return "style is currency but currency is undefined";
1368         }
1369         if (style.compare("unit") == 0 && map.find("unit") == map.end()) {
1370             code = -1;
1371             return "style is unit but unit is undefined";
1372         }
1373     }
1374     if (map.find("currency") != map.end()) {
1375         std::string currency = map["currency"];
1376         std::string checkCurr = GetCurrencyFromConfig(currency);
1377         if (checkCurr.empty()) {
1378             code = -1;
1379             return "not a wellformed code";
1380         }
1381     }
1382     if (map.find("localeMatcher") != map.end()) {
1383         I18nErrorCode status = I18nErrorCode::SUCCESS;
1384         std::string localeMatcher = LocaleHelper::ParseOption(map, "localeMatcher", "best fit", false, status);
1385         if (status != I18nErrorCode::SUCCESS) {
1386             code = -1;
1387             return "getStringOption failed";
1388         }
1389     }
1390     if (map.find("currencySign") != map.end()) {
1391         std::string currencySign = map["currencySign"];
1392         if (currencySign.compare("standard") != 0 && currencySign.compare("accounting") != 0) {
1393             code = -1;
1394             return "getStringOption failed";
1395         }
1396     }
1397     return "";
1398 }
1399 
CheckNumberFormatOptionsExt(std::map<std::string,std::string> & map,int32_t & code,const std::string & optionName,int min,int max)1400 void NumberFormat::CheckNumberFormatOptionsExt(std::map<std::string, std::string> &map, int32_t &code,
1401     const std::string &optionName, int min, int max)
1402 {
1403     if (map.find(optionName) != map.end()) {
1404         std::string optionNameStr = map[optionName];
1405         int32_t status = 0;
1406         int32_t optionValue = ConvertString2Int(optionNameStr, status);
1407         if (status != 0) {
1408             code = -1;
1409             return;
1410         }
1411         if (optionValue < min || optionValue > max) {
1412             code = -1;
1413         }
1414     }
1415 }
1416 
DealWithUnitUsage(bool isFormatRange,double & firstNumber,double & secondNumber)1417 void NumberFormat::DealWithUnitUsage(bool isFormatRange, double& firstNumber, double& secondNumber)
1418 {
1419     if (!createSuccess) {
1420         HILOG_ERROR_I18N("NumberFormat::DealWithUnitUsage: init numberRangeFormat failed.");
1421         return;
1422     }
1423     if (unitUsage.empty()) {
1424         return;
1425     }
1426     double finalNumber = firstNumber;
1427     std::string finalUnit = unit;
1428     if (!NumberFormat::DealWithUnitConvert(finalNumber, finalUnit)) {
1429         HILOG_ERROR_I18N("NumberFormat::DealWithUnitUsage: Deal with unit convert failed.");
1430         return;
1431     }
1432     if (isFormatRange) {
1433         if (!Convert(secondNumber, unit, unitMeasSys, finalUnit, unitMeasSys)) {
1434             HILOG_ERROR_I18N("NumberFormat::DealWithUnitUsage: Convert secondNumber failed.");
1435             return;
1436         }
1437     }
1438     firstNumber = finalNumber;
1439     SetUnit(finalUnit);
1440 }
1441 
DealWithUnitConvert(double & finalNumber,std::string & finalUnit)1442 bool NumberFormat::DealWithUnitConvert(double& finalNumber, std::string& finalUnit)
1443 {
1444     if (UNIT_USAGE_FILE.find(unitUsage) != UNIT_USAGE_FILE.end()) {
1445         if (!ConvertByte(finalNumber, finalUnit)) {
1446             HILOG_ERROR_I18N("NumberFormat::DealWithUnitConvert: Convert byte failed.");
1447             return false;
1448         }
1449         SetPrecisionWithByte(finalNumber, finalUnit);
1450     } else if (UNIT_USAGE_TEMPERATURE.find(unitUsage) != UNIT_USAGE_TEMPERATURE.end()) {
1451         if (preferredTemperature.empty() ||
1452             Convert(finalNumber, unit, unitMeasSys, preferredTemperature, unitMeasSys) == 0) {
1453             return false;
1454         }
1455         finalUnit = preferredTemperature;
1456     } else {
1457         if (localeInfo == nullptr) {
1458             HILOG_ERROR_I18N("NumberFormat::DealWithUnitConvert: localeInfo is nullptr.");
1459             return false;
1460         }
1461         std::vector<std::string> preferredUnits;
1462         if (unitUsage == "default") {
1463             GetDefaultPreferredUnit(localeInfo->GetRegion(), unitType, preferredUnits);
1464         } else {
1465             GetPreferredUnit(localeInfo->GetRegion(), unitUsage, preferredUnits);
1466         }
1467         std::map<double, std::string> preferredValuesOverOne;
1468         std::map<double, std::string> preferredValuesUnderOne;
1469         double num = finalNumber;
1470         for (size_t i = 0; i < preferredUnits.size(); i++) {
1471             if (!Convert(num, unit, unitMeasSys, preferredUnits[i], unitMeasSys)) {
1472                 HILOG_ERROR_I18N("NumberFormat::DealWithUnitConvert: Convert %{public}s failed.", unit.c_str());
1473                 continue;
1474             }
1475             if (num >= 1) {
1476                 preferredValuesOverOne.insert(std::make_pair(num, preferredUnits[i]));
1477             } else {
1478                 preferredValuesUnderOne.insert(std::make_pair(num, preferredUnits[i]));
1479             }
1480         }
1481         if (preferredValuesOverOne.empty() && preferredValuesUnderOne.empty()) {
1482             return false;
1483         }
1484         if (preferredValuesOverOne.size() > 0) {
1485             std::tie(finalNumber, finalUnit) = *preferredValuesOverOne.begin();
1486         } else if (preferredValuesUnderOne.size() > 0) {
1487             std::tie(finalNumber, finalUnit) = *preferredValuesUnderOne.begin();
1488         }
1489     }
1490     return true;
1491 }
1492 
ToMeasureUnit(const std::string & sanctionedUnit,icu::MeasureUnit & measureUnit)1493 bool NumberFormat::ToMeasureUnit(const std::string &sanctionedUnit,
1494     icu::MeasureUnit &measureUnit)
1495 {
1496     for (auto &unitItem : unitArray) {
1497         if (std::strcmp(sanctionedUnit.c_str(), unitItem.getSubtype()) == 0) {
1498             measureUnit = unitItem;
1499             return true;
1500         }
1501     }
1502     return false;
1503 }
1504 
IsWellFormedUnitIdentifier(icu::MeasureUnit & icuUnit,icu::MeasureUnit & icuPerUnit)1505 bool NumberFormat::IsWellFormedUnitIdentifier(icu::MeasureUnit &icuUnit,
1506     icu::MeasureUnit &icuPerUnit)
1507 {
1508     icu::MeasureUnit emptyUnit = icu::MeasureUnit();
1509     auto pos = unit.find("-per-");
1510     if (ToMeasureUnit(unit, icuUnit) && pos == std::string::npos) {
1511         icuPerUnit = emptyUnit;
1512         return true;
1513     }
1514     size_t afterPos = pos + NumberFormat::PERUNIT_STRING;
1515     if (pos == std::string::npos || unit.find("-per-", afterPos) != std::string::npos) {
1516         HILOG_ERROR_I18N("IsWellFormedUnitIdentifier: invalid unit: %{public}s", unit.c_str());
1517         return false;
1518     }
1519     std::string numerator = unit.substr(0, pos);
1520     if (!ToMeasureUnit(numerator, icuUnit)) {
1521         HILOG_ERROR_I18N("IsWellFormedUnitIdentifier: before unit: %{public}s invalid", numerator.c_str());
1522         return false;
1523     }
1524     std::string denominator = unit.substr(pos + NumberFormat::PERUNIT_STRING);
1525     if (!ToMeasureUnit(denominator, icuPerUnit)) {
1526         HILOG_ERROR_I18N("IsWellFormedUnitIdentifier: after unit: %{public}s invalid", denominator.c_str());
1527         return false;
1528     }
1529     return true;
1530 }
1531 
GetNumberPatternSample(const std::string & localeTag,const std::pair<std::string,std::string> & numberPattern)1532 std::string NumberFormat::GetNumberPatternSample(const std::string& localeTag,
1533     const std::pair<std::string, std::string>& numberPattern)
1534 {
1535     UErrorCode status = U_ZERO_ERROR;
1536     icu::Locale icuLocale = icu::Locale::forLanguageTag(icu::StringPiece(localeTag), status);
1537     if (U_FAILURE(status)) {
1538         HILOG_ERROR_I18N("NumberFormat::GetNumberPatternSample: Create icu::Locale failed.");
1539         return "";
1540     }
1541 
1542     icu::DecimalFormatSymbols* decimalFormatSymbols = new icu::DecimalFormatSymbols(icuLocale, status);
1543     if (U_FAILURE(status) || decimalFormatSymbols == nullptr) {
1544         delete decimalFormatSymbols;
1545         HILOG_ERROR_I18N("NumberFormat::GetNumberPatternSample: Create icu::DecimalFormatSymbols failed.");
1546         return "";
1547     }
1548     icu::number::UnlocalizedNumberFormatter tempFormatter = icu::number::NumberFormatter::with();
1549     std::string groupingSymbol = numberPattern.first;
1550     if (groupingSymbol.empty()) {
1551         tempFormatter = tempFormatter.grouping(UNumberGroupingStrategy::UNUM_GROUPING_OFF);
1552     } else {
1553         decimalFormatSymbols->setSymbol(icu::DecimalFormatSymbols::ENumberFormatSymbol::kGroupingSeparatorSymbol,
1554             groupingSymbol.c_str());
1555     }
1556     std::string decimalSymbol = numberPattern.second;
1557     if (!decimalSymbol.empty()) {
1558         decimalFormatSymbols->setSymbol(icu::DecimalFormatSymbols::ENumberFormatSymbol::kDecimalSeparatorSymbol,
1559             decimalSymbol.c_str());
1560     }
1561     tempFormatter = tempFormatter.symbols(*decimalFormatSymbols);
1562     delete decimalFormatSymbols;
1563     icu::number::LocalizedNumberFormatter numberFormat = tempFormatter.locale(icuLocale);
1564     icu::number::FormattedNumber formattedNumber = numberFormat.formatDouble(DEFAULT_SAMPLE_NUMBER, status);
1565     if (U_FAILURE(status)) {
1566         HILOG_ERROR_I18N("NumberFormat::GetNumberPatternSample: Format double failed.");
1567         return "";
1568     }
1569     icu::UnicodeString formatResult = formattedNumber.toString(status);
1570     if (U_FAILURE(status)) {
1571         HILOG_ERROR_I18N("NumberFormat::GetNumberPatternSample: ToString failed.");
1572         return "";
1573     }
1574     std::string result;
1575     formatResult.toUTF8String(result);
1576     return result;
1577 }
1578 } // namespace I18n
1579 } // namespace Global
1580 } // namespace OHOS
1581