1 /********************************************************************
2 * Copyright (C) 2016 and later: Unicode, Inc. and others.
3 * License & terms of use: http://www.unicode.org/copyright.html#License
4 *************************************************************************
5 *************************************************************************
7 * Copyright (c) 1999-2014, International Business Machines Corporation and
8 * others. All Rights Reserved.
9 *************************************************************************/
11 #include "unicode/utypes.h"
12 #include "unicode/unistr.h"
13 #include "unicode/numfmt.h"
14 #include "unicode/dcfmtsym.h"
15 #include "unicode/decimfmt.h"
16 #include "unicode/locid.h"
17 #include "unicode/uclean.h"
23 extern "C" void capi();
27 showCurrencyFormatting(UBool useICU26API);
29 int main(int argc, char **argv) {
30 printf("%s output is in UTF-8\n", argv[0]);
38 showCurrencyFormatting(FALSE);
39 showCurrencyFormatting(TRUE);
41 u_cleanup(); // Release any additional storage held by ICU.
43 printf("Exiting successfully\n");
48 * Sample code for the C++ API to NumberFormat.
51 Locale us("en", "US");
52 UErrorCode status = U_ZERO_ERROR;
54 // Create a number formatter for the US locale
55 NumberFormat *fmt = NumberFormat::createInstance(us, status);
56 check(status, "NumberFormat::createInstance");
58 // Parse a string. The string uses the digits '0' through '9'
59 // and the decimal separator '.', standard in the US locale
60 UnicodeString str("9876543210.123");
62 fmt->parse(str, result, status);
63 check(status, "NumberFormat::parse");
65 printf("NumberFormat::parse(\""); // Display the result
68 uprintf(formattableToString(result));
71 // Take the number parsed above, and use the formatter to
73 str.remove(); // format() will APPEND to this string
74 fmt->format(result, str, status);
75 check(status, "NumberFormat::format");
77 printf("NumberFormat::format("); // Display the result
78 uprintf(formattableToString(result));
83 delete fmt; // Release the storage used by the formatter
87 // currency formatting ----------------------------------------------------- ***
90 * Set a currency on a NumberFormat with pre-ICU 2.6 APIs.
91 * This is a "hack" that will not work properly for all cases because
92 * only ICU 2.6 introduced a more complete framework and data for this.
94 * @param nf The NumberFormat on which to set the currency; takes effect on
95 * currency-formatting NumberFormat instances.
96 * This must actually be a DecimalFormat instance.
97 * The display style of the output is controlled by nf (its pattern,
98 * usually from the display locale ID used to create this instance)
99 * while the currency symbol and number of decimals are set for
101 * @param currency The 3-letter ISO 4217 currency code, NUL-terminated.
102 * @param errorCode ICU error code, must pass U_SUCCESS() on input.
105 setNumberFormatCurrency_2_4(NumberFormat &nf, const char *currency, UErrorCode &errorCode) {
107 if(U_FAILURE(errorCode)) {
110 if(currency==NULL || strlen(currency)!=3) {
111 errorCode=U_ILLEGAL_ARGUMENT_ERROR;
115 // check that the formatter is a DecimalFormat instance
116 // necessary because we will cast to the DecimalFormat subclass to set
117 // the currency symbol
118 DecimalFormat *dnf=dynamic_cast<DecimalFormat *>(&nf);
120 errorCode=U_ILLEGAL_ARGUMENT_ERROR;
124 // map the currency code to a locale ID
125 // only the currencies in this array are supported
126 // it would be possible to map to a locale ID, instantiate a currency
127 // formatter for that and copy its values, but that would be slower,
128 // and we have to hardcode something here anyway
129 static const struct {
131 const char *currency;
133 // fractionDigits==minimumFractionDigits==maximumFractionDigits
134 // for these currencies
135 int32_t fractionDigits;
138 * Set the rounding increment to 0 if it is implied with the number of
139 * fraction digits. Setting an explicit rounding increment makes
140 * number formatting slower.
141 * In other words, set it to something other than 0 only for unusual
142 * cases like "nickel rounding" (0.05) when the increment differs from
143 * 10^(-maximumFractionDigits).
145 double roundingIncrement;
147 // Unicode string with the desired currency display symbol or name
150 { "USD", 2, 0.0, { 0x24, 0 } },
151 { "GBP", 2, 0.0, { 0xa3, 0 } },
152 { "EUR", 2, 0.0, { 0x20ac, 0 } },
153 { "JPY", 0, 0.0, { 0xa5, 0 } }
158 for(i=0; i<UPRV_LENGTHOF(currencyMap); ++i) {
159 if(strcmp(currency, currencyMap[i].currency)==0) {
163 if(i==UPRV_LENGTHOF(currencyMap)) {
164 // a more specific error code would be useful in a real application
165 errorCode=U_UNSUPPORTED_ERROR;
169 // set the currency-related data into the caller's formatter
171 nf.setMinimumFractionDigits(currencyMap[i].fractionDigits);
172 nf.setMaximumFractionDigits(currencyMap[i].fractionDigits);
174 dnf->setRoundingIncrement(currencyMap[i].roundingIncrement);
176 DecimalFormatSymbols symbols(*dnf->getDecimalFormatSymbols());
177 symbols.setSymbol(DecimalFormatSymbols::kCurrencySymbol, currencyMap[i].symbol);
178 dnf->setDecimalFormatSymbols(symbols); // do not adopt symbols: Jitterbug 2889
182 * Set a currency on a NumberFormat with ICU 2.6 APIs.
184 * @param nf The NumberFormat on which to set the currency; takes effect on
185 * currency-formatting NumberFormat instances.
186 * The display style of the output is controlled by nf (its pattern,
187 * usually from the display locale ID used to create this instance)
188 * while the currency symbol and number of decimals are set for
190 * @param currency The 3-letter ISO 4217 currency code, NUL-terminated.
191 * @param errorCode ICU error code, must pass U_SUCCESS() on input.
194 setNumberFormatCurrency_2_6(NumberFormat &nf, const char *currency, UErrorCode &errorCode) {
195 if(U_FAILURE(errorCode)) {
198 if(currency==NULL || strlen(currency)!=3) {
199 errorCode=U_ILLEGAL_ARGUMENT_ERROR;
203 // invariant-character conversion to UChars (see utypes.h and putil.h)
205 u_charsToUChars(currency, uCurrency, 4);
208 // in ICU 3.0 this API (which was @draft ICU 2.6) gained a UErrorCode& argument
209 #if (U_ICU_VERSION_MAJOR_NUM < 3)
210 nf.setCurrency(uCurrency);
212 nf.setCurrency(uCurrency, errorCode);
216 static const char *const
218 // use locale IDs complete with country code to be sure to
219 // pick up number/currency format patterns
220 "en_US", "en_GB", "de_DE", "ja_JP", "fr_FR", "hi_IN"
223 static const char *const
225 "USD", "GBP", "EUR", "JPY"
229 showCurrencyFormatting(UBool useICU26API) {
233 UnicodeString output;
235 UErrorCode errorCode;
237 // TODO: Using printf() here assumes that the runtime encoding is ASCII-friendly
238 // and can therefore be mixed with UTF-8
240 for(i=0; i<UPRV_LENGTHOF(sampleLocaleIDs); ++i) {
241 printf("show currency formatting (method for %s) in the locale \"%s\"\n",
242 useICU26API ? "ICU 2.6" : "before ICU 2.6",
245 // get a currency formatter for this locale ID
246 errorCode=U_ZERO_ERROR;
247 nf=NumberFormat::createCurrencyInstance(sampleLocaleIDs[i], errorCode);
248 if(U_FAILURE(errorCode)) {
249 printf("NumberFormat::createCurrencyInstance(%s) failed - %s\n",
250 sampleLocaleIDs[i], u_errorName(errorCode));
254 for(j=0; j<UPRV_LENGTHOF(sampleCurrencies); ++j) {
255 printf(" - format currency \"%s\": ", sampleCurrencies[j]);
257 // set the actual currency to be formatted
259 setNumberFormatCurrency_2_6(*nf, sampleCurrencies[j], errorCode);
261 setNumberFormatCurrency_2_4(*nf, sampleCurrencies[j], errorCode);
263 if(U_FAILURE(errorCode)) {
264 printf("setNumberFormatCurrency(%s) failed - %s\n",
265 sampleCurrencies[j], u_errorName(errorCode));
269 // output=formatted currency value
271 nf->format(12345678.93, output);
272 output+=(UChar)0x0a; // '\n'