1 // © 2020 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 
4 #ifndef __UNUMBERRANGEFORMATTER_H__
5 #define __UNUMBERRANGEFORMATTER_H__
6 
7 #include "unicode/utypes.h"
8 
9 #if !UCONFIG_NO_FORMATTING
10 
11 #include "unicode/parseerr.h"
12 #include "unicode/ufieldpositer.h"
13 #include "unicode/umisc.h"
14 #include "unicode/uformattedvalue.h"
15 #include "unicode/uformattable.h"
16 
17 
18 /**
19  * \file
20  * \brief C-compatible API for localized number range formatting.
21  *
22  * This is the C-compatible version of the NumberRangeFormatter API. C++ users
23  * should include unicode/numberrangeformatter.h and use the proper C++ APIs.
24  *
25  * First create a UNumberRangeFormatter, which is immutable, and then format to
26  * a UFormattedNumberRange.
27  *
28  * Example code:
29  * <pre>
30  * // Setup:
31  * UErrorCode ec = U_ZERO_ERROR;
32  * UNumberRangeFormatter* uformatter = unumrf_openForSkeletonCollapseIdentityFallbackAndLocaleWithError(
33  *     u"currency/USD precision-integer",
34  *     -1,
35  *     UNUM_RANGE_COLLAPSE_AUTO,
36  *     UNUM_IDENTITY_FALLBACK_APPROXIMATELY,
37  *     "en-US",
38  *     NULL,
39  *     &ec);
40  * UFormattedNumberRange* uresult = unumrf_openResult(&ec);
41  * if (U_FAILURE(ec)) { return; }
42  *
43  * // Format a double range:
44  * unumrf_formatDoubleRange(uformatter, 3.0, 5.0, uresult, &ec);
45  * if (U_FAILURE(ec)) { return; }
46  *
47  * // Get the result string:
48  * int32_t len;
49  * const UChar* str = ufmtval_getString(unumrf_resultAsValue(uresult, &ec), &len, &ec);
50  * if (U_FAILURE(ec)) { return; }
51  * // str should equal "$3 – $5"
52  *
53  * // Cleanup:
54  * unumf_close(uformatter);
55  * unumf_closeResult(uresult);
56  * </pre>
57  *
58  * If you are a C++ user linking against the C libraries, you can use the LocalPointer versions of these
59  * APIs. The following example uses LocalPointer with the decimal number and field position APIs:
60  *
61  * <pre>
62  * // Setup:
63  * LocalUNumberRangeFormatterPointer uformatter(
64  *     unumrf_openForSkeletonCollapseIdentityFallbackAndLocaleWithError(...));
65  * LocalUFormattedNumberRangePointer uresult(unumrf_openResult(&ec));
66  * if (U_FAILURE(ec)) { return; }
67  *
68  * // Format a double number range:
69  * unumrf_formatDoubleRange(uformatter.getAlias(), 3.0, 5.0, uresult.getAlias(), &ec);
70  * if (U_FAILURE(ec)) { return; }
71  *
72  * // No need to do any cleanup since we are using LocalPointer.
73  * </pre>
74  *
75  * You can also get field positions. For more information, see uformattedvalue.h.
76  */
77 
78 /**
79  * Defines how to merge fields that are identical across the range sign.
80  *
81  * @stable ICU 63
82  */
83 typedef enum UNumberRangeCollapse {
84     /**
85      * Use locale data and heuristics to determine how much of the string to collapse. Could end up collapsing none,
86      * some, or all repeated pieces in a locale-sensitive way.
87      *
88      * The heuristics used for this option are subject to change over time.
89      *
90      * @stable ICU 63
91      */
92     UNUM_RANGE_COLLAPSE_AUTO,
93 
94     /**
95      * Do not collapse any part of the number. Example: "3.2 thousand kilograms – 5.3 thousand kilograms"
96      *
97      * @stable ICU 63
98      */
99     UNUM_RANGE_COLLAPSE_NONE,
100 
101     /**
102      * Collapse the unit part of the number, but not the notation, if present. Example: "3.2 thousand – 5.3 thousand
103      * kilograms"
104      *
105      * @stable ICU 63
106      */
107     UNUM_RANGE_COLLAPSE_UNIT,
108 
109     /**
110      * Collapse any field that is equal across the range sign. May introduce ambiguity on the magnitude of the
111      * number. Example: "3.2 – 5.3 thousand kilograms"
112      *
113      * @stable ICU 63
114      */
115     UNUM_RANGE_COLLAPSE_ALL
116 } UNumberRangeCollapse;
117 
118 /**
119  * Defines the behavior when the two numbers in the range are identical after rounding. To programmatically detect
120  * when the identity fallback is used, compare the lower and upper BigDecimals via FormattedNumber.
121  *
122  * @stable ICU 63
123  * @see NumberRangeFormatter
124  */
125 typedef enum UNumberRangeIdentityFallback {
126     /**
127      * Show the number as a single value rather than a range. Example: "$5"
128      *
129      * @stable ICU 63
130      */
131     UNUM_IDENTITY_FALLBACK_SINGLE_VALUE,
132 
133     /**
134      * Show the number using a locale-sensitive approximation pattern. If the numbers were the same before rounding,
135      * show the single value. Example: "~$5" or "$5"
136      *
137      * @stable ICU 63
138      */
139     UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE,
140 
141     /**
142      * Show the number using a locale-sensitive approximation pattern. Use the range pattern always, even if the
143      * inputs are the same. Example: "~$5"
144      *
145      * @stable ICU 63
146      */
147     UNUM_IDENTITY_FALLBACK_APPROXIMATELY,
148 
149     /**
150      * Show the number as the range of two equal values. Use the range pattern always, even if the inputs are the
151      * same. Example (with RangeCollapse.NONE): "$5 – $5"
152      *
153      * @stable ICU 63
154      */
155     UNUM_IDENTITY_FALLBACK_RANGE
156 } UNumberRangeIdentityFallback;
157 
158 /**
159  * Used in the result class FormattedNumberRange to indicate to the user whether the numbers formatted in the range
160  * were equal or not, and whether or not the identity fallback was applied.
161  *
162  * @stable ICU 63
163  * @see NumberRangeFormatter
164  */
165 typedef enum UNumberRangeIdentityResult {
166     /**
167      * Used to indicate that the two numbers in the range were equal, even before any rounding rules were applied.
168      *
169      * @stable ICU 63
170      * @see NumberRangeFormatter
171      */
172     UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING,
173 
174     /**
175      * Used to indicate that the two numbers in the range were equal, but only after rounding rules were applied.
176      *
177      * @stable ICU 63
178      * @see NumberRangeFormatter
179      */
180     UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING,
181 
182     /**
183      * Used to indicate that the two numbers in the range were not equal, even after rounding rules were applied.
184      *
185      * @stable ICU 63
186      * @see NumberRangeFormatter
187      */
188     UNUM_IDENTITY_RESULT_NOT_EQUAL,
189 
190 #ifndef U_HIDE_INTERNAL_API
191     /**
192      * The number of entries in this enum.
193      * @internal
194      */
195     UNUM_IDENTITY_RESULT_COUNT
196 #endif
197 
198 } UNumberRangeIdentityResult;
199 
200 
201 #ifndef U_HIDE_DRAFT_API
202 
203 struct UNumberRangeFormatter;
204 /**
205  * C-compatible version of icu::number::LocalizedNumberRangeFormatter.
206  *
207  * NOTE: This is a C-compatible API; C++ users should build against numberrangeformatter.h instead.
208  *
209  * @draft ICU 68
210  */
211 typedef struct UNumberRangeFormatter UNumberRangeFormatter;
212 
213 
214 struct UFormattedNumberRange;
215 /**
216  * C-compatible version of icu::number::FormattedNumberRange.
217  *
218  * NOTE: This is a C-compatible API; C++ users should build against numberrangeformatter.h instead.
219  *
220  * @draft ICU 68
221  */
222 typedef struct UFormattedNumberRange UFormattedNumberRange;
223 
224 
225 /**
226  * Creates a new UNumberFormatter for the given skeleton string, collapse option, identity fallback
227  * option, and locale. This is currently the only method for creating a new UNumberRangeFormatter.
228  *
229  * Objects of type UNumberRangeFormatter returned by this method are threadsafe.
230  *
231  * For more details on skeleton strings, see the documentation in numberrangeformatter.h. For more
232  * details on the usage of this API, see the documentation at the top of unumberrangeformatter.h.
233  *
234  * NOTE: This is a C-compatible API; C++ users should build against numberrangeformatter.h instead.
235  *
236  * @param skeleton The skeleton string, like u"percent precision-integer"
237  * @param skeletonLen The number of UChars in the skeleton string, or -1 if it is NUL-terminated.
238  * @param collapse Option for how to merge affixes (if unsure, use UNUM_RANGE_COLLAPSE_AUTO)
239  * @param identityFallback Option for resolving when both sides of the range are equal.
240  * @param locale The NUL-terminated locale ID.
241  * @param perror A parse error struct populated if an error occurs when parsing. Can be NULL.
242  *               If no error occurs, perror->offset will be set to -1.
243  * @param ec Set if an error occurs.
244  * @draft ICU 68
245  */
246 U_CAPI UNumberRangeFormatter* U_EXPORT2
247 unumrf_openForSkeletonWithCollapseAndIdentityFallback(
248     const UChar* skeleton,
249     int32_t skeletonLen,
250     UNumberRangeCollapse collapse,
251     UNumberRangeIdentityFallback identityFallback,
252     const char* locale,
253     UParseError* perror,
254     UErrorCode* ec);
255 
256 
257 /**
258  * Creates an object to hold the result of a UNumberRangeFormatter
259  * operation. The object can be used repeatedly; it is cleared whenever
260  * passed to a format function.
261  *
262  * @param ec Set if an error occurs.
263  * @draft ICU 68
264  */
265 U_CAPI UFormattedNumberRange* U_EXPORT2
266 unumrf_openResult(UErrorCode* ec);
267 
268 
269 /**
270  * Uses a UNumberRangeFormatter to format a range of doubles.
271  *
272  * The UNumberRangeFormatter can be shared between threads. Each thread should have its own local
273  * UFormattedNumberRange, however, for storing the result of the formatting operation.
274  *
275  * NOTE: This is a C-compatible API; C++ users should build against numberrangeformatter.h instead.
276  *
277  * @param uformatter A formatter object; see unumberrangeformatter.h.
278  * @param first The first (usually smaller) number in the range.
279  * @param second The second (usually larger) number in the range.
280  * @param uresult The object that will be mutated to store the result; see unumrf_openResult.
281  * @param ec Set if an error occurs.
282  * @draft ICU 68
283  */
284 U_CAPI void U_EXPORT2
285 unumrf_formatDoubleRange(
286     const UNumberRangeFormatter* uformatter,
287     double first,
288     double second,
289     UFormattedNumberRange* uresult,
290     UErrorCode* ec);
291 
292 
293 /**
294  * Uses a UNumberRangeFormatter to format a range of decimal numbers.
295  *
296  * With a decimal number string, you can specify an input with arbitrary precision.
297  *
298  * The UNumberRangeFormatter can be shared between threads. Each thread should have its own local
299  * UFormattedNumberRange, however, for storing the result of the formatting operation.
300  *
301  * NOTE: This is a C-compatible API; C++ users should build against numberrangeformatter.h instead.
302  *
303  * @param uformatter A formatter object; see unumberrangeformatter.h.
304  * @param first The first (usually smaller) number in the range.
305  * @param firstLen The length of the first decimal number string.
306  * @param second The second (usually larger) number in the range.
307  * @param secondLen The length of the second decimal number string.
308  * @param uresult The object that will be mutated to store the result; see unumrf_openResult.
309  * @param ec Set if an error occurs.
310  * @draft ICU 68
311  */
312 U_CAPI void U_EXPORT2
313 unumrf_formatDecimalRange(
314     const UNumberRangeFormatter* uformatter,
315     const char* first,
316     int32_t firstLen,
317     const char* second,
318     int32_t secondLen,
319     UFormattedNumberRange* uresult,
320     UErrorCode* ec);
321 
322 
323 /**
324  * Returns a representation of a UFormattedNumberRange as a UFormattedValue,
325  * which can be subsequently passed to any API requiring that type.
326  *
327  * The returned object is owned by the UFormattedNumberRange and is valid
328  * only as long as the UFormattedNumber is present and unchanged in memory.
329  *
330  * You can think of this method as a cast between types.
331  *
332  * @param uresult The object containing the formatted number range.
333  * @param ec Set if an error occurs.
334  * @return A UFormattedValue owned by the input object.
335  * @draft ICU 68
336  */
337 U_CAPI const UFormattedValue* U_EXPORT2
338 unumrf_resultAsValue(const UFormattedNumberRange* uresult, UErrorCode* ec);
339 
340 
341 /**
342  * Extracts the identity result from a UFormattedNumberRange.
343  *
344  * NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead.
345  *
346  * @param uresult The object containing the formatted number range.
347  * @param ec Set if an error occurs.
348  * @return The identity result; see UNumberRangeIdentityResult.
349  * @draft ICU 68
350  */
351 U_CAPI UNumberRangeIdentityResult U_EXPORT2
352 unumrf_resultGetIdentityResult(
353     const UFormattedNumberRange* uresult,
354     UErrorCode* ec);
355 
356 
357 #ifndef U_HIDE_DRAFT_API
358 /**
359  * Extracts the first formatted number as a decimal number. This endpoint
360  * is useful for obtaining the exact number being printed after scaling
361  * and rounding have been applied by the number range formatting pipeline.
362  *
363  * The syntax of the unformatted number is a "numeric string"
364  * as defined in the Decimal Arithmetic Specification, available at
365  * http://speleotrove.com/decimal
366  *
367  * @param  uresult       The input object containing the formatted number range.
368  * @param  dest          the 8-bit char buffer into which the decimal number is placed
369  * @param  destCapacity  The size, in chars, of the destination buffer.  May be zero
370  *                       for precomputing the required size.
371  * @param  ec            receives any error status.
372  *                       If U_BUFFER_OVERFLOW_ERROR: Returns number of chars for
373  *                       preflighting.
374  * @return Number of chars in the data.  Does not include a trailing NUL.
375  * @draft ICU 68
376  */
377 U_CAPI int32_t U_EXPORT2
378 unumrf_resultGetFirstDecimalNumber(
379     const UFormattedNumberRange* uresult,
380     char* dest,
381     int32_t destCapacity,
382     UErrorCode* ec);
383 
384 
385 /**
386  * Extracts the second formatted number as a decimal number. This endpoint
387  * is useful for obtaining the exact number being printed after scaling
388  * and rounding have been applied by the number range formatting pipeline.
389  *
390  * The syntax of the unformatted number is a "numeric string"
391  * as defined in the Decimal Arithmetic Specification, available at
392  * http://speleotrove.com/decimal
393  *
394  * @param  uresult       The input object containing the formatted number range.
395  * @param  dest          the 8-bit char buffer into which the decimal number is placed
396  * @param  destCapacity  The size, in chars, of the destination buffer.  May be zero
397  *                       for precomputing the required size.
398  * @param  ec            receives any error status.
399  *                       If U_BUFFER_OVERFLOW_ERROR: Returns number of chars for
400  *                       preflighting.
401  * @return Number of chars in the data.  Does not include a trailing NUL.
402  * @draft ICU 68
403  */
404 U_CAPI int32_t U_EXPORT2
405 unumrf_resultGetSecondDecimalNumber(
406     const UFormattedNumberRange* uresult,
407     char* dest,
408     int32_t destCapacity,
409     UErrorCode* ec);
410 #endif // U_HIDE_DRAFT_API
411 
412 
413 /**
414  * Releases the UNumberFormatter created by unumf_openForSkeletonAndLocale().
415  *
416  * @param uformatter An object created by unumf_openForSkeletonAndLocale().
417  * @draft ICU 68
418  */
419 U_CAPI void U_EXPORT2
420 unumrf_close(UNumberRangeFormatter* uformatter);
421 
422 
423 /**
424  * Releases the UFormattedNumber created by unumf_openResult().
425  *
426  * @param uresult An object created by unumf_openResult().
427  * @draft ICU 68
428  */
429 U_CAPI void U_EXPORT2
430 unumrf_closeResult(UFormattedNumberRange* uresult);
431 
432 
433 #if U_SHOW_CPLUSPLUS_API
434 U_NAMESPACE_BEGIN
435 
436 /**
437  * \class LocalUNumberRangeFormatterPointer
438  * "Smart pointer" class; closes a UNumberFormatter via unumf_close().
439  * For most methods see the LocalPointerBase base class.
440  *
441  * Usage:
442  * <pre>
443  * LocalUNumberRangeFormatterPointer uformatter(
444  *     unumrf_openForSkeletonCollapseIdentityFallbackAndLocaleWithError(...));
445  * // no need to explicitly call unumrf_close()
446  * </pre>
447  *
448  * @see LocalPointerBase
449  * @see LocalPointer
450  * @draft ICU 68
451  */
452 U_DEFINE_LOCAL_OPEN_POINTER(LocalUNumberRangeFormatterPointer, UNumberRangeFormatter, unumrf_close);
453 
454 /**
455  * \class LocalUFormattedNumberPointer
456  * "Smart pointer" class; closes a UFormattedNumber via unumf_closeResult().
457  * For most methods see the LocalPointerBase base class.
458  *
459  * Usage:
460  * <pre>
461  * LocalUFormattedNumberRangePointer uresult(unumrf_openResult(...));
462  * // no need to explicitly call unumrf_closeResult()
463  * </pre>
464  *
465  * @see LocalPointerBase
466  * @see LocalPointer
467  * @draft ICU 68
468  */
469 U_DEFINE_LOCAL_OPEN_POINTER(LocalUFormattedNumberRangePointer, UFormattedNumberRange, unumrf_closeResult);
470 
471 U_NAMESPACE_END
472 #endif // U_SHOW_CPLUSPLUS_API
473 
474 #endif // U_HIDE_DRAFT_API
475 
476 #endif /* #if !UCONFIG_NO_FORMATTING */
477 #endif //__UNUMBERRANGEFORMATTER_H__
478