mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-13 08:53:20 +00:00
parent
ab086feaa0
commit
2ea56b531a
14 changed files with 759 additions and 130 deletions
|
@ -229,6 +229,7 @@
|
|||
<ClCompile Include="numparse_affixes.cpp" />
|
||||
<ClCompile Include="numparse_compositions.cpp" />
|
||||
<ClCompile Include="numparse_validators.cpp" />
|
||||
<ClCompile Include="numrange_capi.cpp" />
|
||||
<ClCompile Include="numrange_fluent.cpp" />
|
||||
<ClCompile Include="numrange_impl.cpp" />
|
||||
<ClCompile Include="numfmt.cpp" />
|
||||
|
|
|
@ -639,6 +639,9 @@
|
|||
<ClCompile Include="numparse_validators.cpp">
|
||||
<Filter>formatting</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="numrange_capi.cpp">
|
||||
<Filter>formatting</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="numrange_fluent.cpp">
|
||||
<Filter>formatting</Filter>
|
||||
</ClCompile>
|
||||
|
|
|
@ -450,6 +450,7 @@
|
|||
<ClCompile Include="numparse_affixes.cpp" />
|
||||
<ClCompile Include="numparse_compositions.cpp" />
|
||||
<ClCompile Include="numparse_validators.cpp" />
|
||||
<ClCompile Include="numrange_capi.cpp" />
|
||||
<ClCompile Include="numrange_fluent.cpp" />
|
||||
<ClCompile Include="numrange_impl.cpp" />
|
||||
<ClCompile Include="numfmt.cpp" />
|
||||
|
|
149
icu4c/source/i18n/numrange_capi.cpp
Normal file
149
icu4c/source/i18n/numrange_capi.cpp
Normal file
|
@ -0,0 +1,149 @@
|
|||
// © 2018 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
// Allow implicit conversion from char16_t* to UnicodeString for this file:
|
||||
// Helpful in toString methods and elsewhere.
|
||||
#define UNISTR_FROM_STRING_EXPLICIT
|
||||
|
||||
#include "fphdlimp.h"
|
||||
#include "number_utypes.h"
|
||||
#include "numparse_types.h"
|
||||
#include "formattedval_impl.h"
|
||||
#include "numrange_impl.h"
|
||||
#include "unicode/numberrangeformatter.h"
|
||||
#include "unicode/unumberrangeformatter.h"
|
||||
|
||||
using namespace icu;
|
||||
using namespace icu::number;
|
||||
using namespace icu::number::impl;
|
||||
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
namespace number {
|
||||
namespace impl {
|
||||
|
||||
/**
|
||||
* Implementation class for UNumberRangeFormatter. Wraps a LocalizedRangeNumberFormatter.
|
||||
*/
|
||||
struct UNumberRangeFormatterData : public UMemory,
|
||||
// Magic number as ASCII == "NRF" (NumberRangeFormatter)
|
||||
public IcuCApiHelper<UNumberRangeFormatter, UNumberRangeFormatterData, 0x4E524600> {
|
||||
LocalizedNumberRangeFormatter fFormatter;
|
||||
};
|
||||
|
||||
struct UFormattedNumberRangeImpl;
|
||||
|
||||
// Magic number as ASCII == "FDN" (FormatteDNumber)
|
||||
typedef IcuCApiHelper<UFormattedNumberRange, UFormattedNumberRangeImpl, 0x46444E00> UFormattedNumberRangeApiHelper;
|
||||
|
||||
struct UFormattedNumberRangeImpl : public UFormattedValueImpl, public UFormattedNumberRangeApiHelper {
|
||||
UFormattedNumberRangeImpl();
|
||||
~UFormattedNumberRangeImpl();
|
||||
|
||||
FormattedNumberRange fImpl;
|
||||
UFormattedNumberRangeData fData;
|
||||
};
|
||||
|
||||
UFormattedNumberRangeImpl::UFormattedNumberRangeImpl()
|
||||
: fImpl(&fData) {
|
||||
fFormattedValue = &fImpl;
|
||||
}
|
||||
|
||||
UFormattedNumberRangeImpl::~UFormattedNumberRangeImpl() {
|
||||
// Disown the data from fImpl so it doesn't get deleted twice
|
||||
fImpl.fData = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
U_NAMESPACE_END
|
||||
|
||||
|
||||
UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(
|
||||
UFormattedNumberRange,
|
||||
UFormattedNumberRangeImpl,
|
||||
UFormattedNumberRangeApiHelper,
|
||||
unumrf)
|
||||
|
||||
|
||||
U_CAPI UNumberRangeFormatter* U_EXPORT2
|
||||
unumrf_openForSkeletonWithCollapseAndIdentityFallback(
|
||||
const UChar* skeleton,
|
||||
int32_t skeletonLen,
|
||||
UNumberRangeCollapse collapse,
|
||||
UNumberRangeIdentityFallback identityFallback,
|
||||
const char* locale,
|
||||
UParseError* perror,
|
||||
UErrorCode* ec) {
|
||||
auto* impl = new UNumberRangeFormatterData();
|
||||
if (impl == nullptr) {
|
||||
*ec = U_MEMORY_ALLOCATION_ERROR;
|
||||
return nullptr;
|
||||
}
|
||||
// Readonly-alias constructor (first argument is whether we are NUL-terminated)
|
||||
UnicodeString skeletonString(skeletonLen == -1, skeleton, skeletonLen);
|
||||
impl->fFormatter = NumberRangeFormatter::withLocale(locale)
|
||||
.numberFormatterBoth(NumberFormatter::forSkeleton(skeletonString, *perror, *ec))
|
||||
.collapse(collapse)
|
||||
.identityFallback(identityFallback);
|
||||
return impl->exportForC();
|
||||
}
|
||||
|
||||
U_CAPI void U_EXPORT2
|
||||
unumrf_formatDoubleRange(
|
||||
const UNumberRangeFormatter* uformatter,
|
||||
double first,
|
||||
double second,
|
||||
UFormattedNumberRange* uresult,
|
||||
UErrorCode* ec) {
|
||||
const UNumberRangeFormatterData* formatter = UNumberRangeFormatterData::validate(uformatter, *ec);
|
||||
auto* result = UFormattedNumberRangeApiHelper::validate(uresult, *ec);
|
||||
if (U_FAILURE(*ec)) { return; }
|
||||
|
||||
result->fData.getStringRef().clear();
|
||||
result->fData.quantity1.setToDouble(first);
|
||||
result->fData.quantity2.setToDouble(second);
|
||||
formatter->fFormatter.formatImpl(result->fData, first == second, *ec);
|
||||
}
|
||||
|
||||
U_CAPI void U_EXPORT2
|
||||
unumrf_formatDecimalRange(
|
||||
const UNumberRangeFormatter* uformatter,
|
||||
const char* first, int32_t firstLen,
|
||||
const char* second, int32_t secondLen,
|
||||
UFormattedNumberRange* uresult,
|
||||
UErrorCode* ec) {
|
||||
const UNumberRangeFormatterData* formatter = UNumberRangeFormatterData::validate(uformatter, *ec);
|
||||
auto* result = UFormattedNumberRangeApiHelper::validate(uresult, *ec);
|
||||
if (U_FAILURE(*ec)) { return; }
|
||||
|
||||
result->fData.getStringRef().clear();
|
||||
result->fData.quantity1.setToDecNumber({first, firstLen}, *ec);
|
||||
result->fData.quantity2.setToDecNumber({second, secondLen}, *ec);
|
||||
formatter->fFormatter.formatImpl(result->fData, first == second, *ec);
|
||||
}
|
||||
|
||||
U_CAPI UNumberRangeIdentityResult U_EXPORT2
|
||||
unumrf_resultGetIdentityResult(
|
||||
const UFormattedNumberRange* uresult,
|
||||
UErrorCode* ec) {
|
||||
auto* result = UFormattedNumberRangeApiHelper::validate(uresult, *ec);
|
||||
if (U_FAILURE(*ec)) {
|
||||
return UNUM_IDENTITY_RESULT_COUNT;
|
||||
}
|
||||
return result->fData.identityResult;
|
||||
}
|
||||
|
||||
U_CAPI void U_EXPORT2
|
||||
unumrf_close(UNumberRangeFormatter* f) {
|
||||
UErrorCode localStatus = U_ZERO_ERROR;
|
||||
const UNumberRangeFormatterData* impl = UNumberRangeFormatterData::validate(f, localStatus);
|
||||
delete impl;
|
||||
}
|
||||
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
|
@ -133,6 +133,7 @@ numparse_parsednumber.cpp
|
|||
numparse_scientific.cpp
|
||||
numparse_symbols.cpp
|
||||
numparse_validators.cpp
|
||||
numrange_capi.cpp
|
||||
numrange_fluent.cpp
|
||||
numrange_impl.cpp
|
||||
numsys.cpp
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "unicode/formattedvalue.h"
|
||||
#include "unicode/fpositer.h"
|
||||
#include "unicode/numberformatter.h"
|
||||
#include "unicode/unumberrangeformatter.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
|
@ -31,7 +32,7 @@
|
|||
* .numberFormatterFirst(NumberFormatter::with().adoptUnit(MeasureUnit::createMeter()))
|
||||
* .numberFormatterSecond(NumberFormatter::with().adoptUnit(MeasureUnit::createKilometer()))
|
||||
* .locale("en-GB")
|
||||
* .formatRange(750, 1.2, status)
|
||||
* .formatFormattableRange(750, 1.2, status)
|
||||
* .toString(status);
|
||||
* // => "750 m - 1.2 km"
|
||||
* </pre>
|
||||
|
@ -44,128 +45,6 @@
|
|||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Defines how to merge fields that are identical across the range sign.
|
||||
*
|
||||
* @stable ICU 63
|
||||
*/
|
||||
typedef enum UNumberRangeCollapse {
|
||||
/**
|
||||
* Use locale data and heuristics to determine how much of the string to collapse. Could end up collapsing none,
|
||||
* some, or all repeated pieces in a locale-sensitive way.
|
||||
*
|
||||
* The heuristics used for this option are subject to change over time.
|
||||
*
|
||||
* @stable ICU 63
|
||||
*/
|
||||
UNUM_RANGE_COLLAPSE_AUTO,
|
||||
|
||||
/**
|
||||
* Do not collapse any part of the number. Example: "3.2 thousand kilograms – 5.3 thousand kilograms"
|
||||
*
|
||||
* @stable ICU 63
|
||||
*/
|
||||
UNUM_RANGE_COLLAPSE_NONE,
|
||||
|
||||
/**
|
||||
* Collapse the unit part of the number, but not the notation, if present. Example: "3.2 thousand – 5.3 thousand
|
||||
* kilograms"
|
||||
*
|
||||
* @stable ICU 63
|
||||
*/
|
||||
UNUM_RANGE_COLLAPSE_UNIT,
|
||||
|
||||
/**
|
||||
* Collapse any field that is equal across the range sign. May introduce ambiguity on the magnitude of the
|
||||
* number. Example: "3.2 – 5.3 thousand kilograms"
|
||||
*
|
||||
* @stable ICU 63
|
||||
*/
|
||||
UNUM_RANGE_COLLAPSE_ALL
|
||||
} UNumberRangeCollapse;
|
||||
|
||||
/**
|
||||
* Defines the behavior when the two numbers in the range are identical after rounding. To programmatically detect
|
||||
* when the identity fallback is used, compare the lower and upper BigDecimals via FormattedNumber.
|
||||
*
|
||||
* @stable ICU 63
|
||||
* @see NumberRangeFormatter
|
||||
*/
|
||||
typedef enum UNumberRangeIdentityFallback {
|
||||
/**
|
||||
* Show the number as a single value rather than a range. Example: "$5"
|
||||
*
|
||||
* @stable ICU 63
|
||||
*/
|
||||
UNUM_IDENTITY_FALLBACK_SINGLE_VALUE,
|
||||
|
||||
/**
|
||||
* Show the number using a locale-sensitive approximation pattern. If the numbers were the same before rounding,
|
||||
* show the single value. Example: "~$5" or "$5"
|
||||
*
|
||||
* @stable ICU 63
|
||||
*/
|
||||
UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE,
|
||||
|
||||
/**
|
||||
* Show the number using a locale-sensitive approximation pattern. Use the range pattern always, even if the
|
||||
* inputs are the same. Example: "~$5"
|
||||
*
|
||||
* @stable ICU 63
|
||||
*/
|
||||
UNUM_IDENTITY_FALLBACK_APPROXIMATELY,
|
||||
|
||||
/**
|
||||
* Show the number as the range of two equal values. Use the range pattern always, even if the inputs are the
|
||||
* same. Example (with RangeCollapse.NONE): "$5 – $5"
|
||||
*
|
||||
* @stable ICU 63
|
||||
*/
|
||||
UNUM_IDENTITY_FALLBACK_RANGE
|
||||
} UNumberRangeIdentityFallback;
|
||||
|
||||
/**
|
||||
* Used in the result class FormattedNumberRange to indicate to the user whether the numbers formatted in the range
|
||||
* were equal or not, and whether or not the identity fallback was applied.
|
||||
*
|
||||
* @stable ICU 63
|
||||
* @see NumberRangeFormatter
|
||||
*/
|
||||
typedef enum UNumberRangeIdentityResult {
|
||||
/**
|
||||
* Used to indicate that the two numbers in the range were equal, even before any rounding rules were applied.
|
||||
*
|
||||
* @stable ICU 63
|
||||
* @see NumberRangeFormatter
|
||||
*/
|
||||
UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING,
|
||||
|
||||
/**
|
||||
* Used to indicate that the two numbers in the range were equal, but only after rounding rules were applied.
|
||||
*
|
||||
* @stable ICU 63
|
||||
* @see NumberRangeFormatter
|
||||
*/
|
||||
UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING,
|
||||
|
||||
/**
|
||||
* Used to indicate that the two numbers in the range were not equal, even after rounding rules were applied.
|
||||
*
|
||||
* @stable ICU 63
|
||||
* @see NumberRangeFormatter
|
||||
*/
|
||||
UNUM_IDENTITY_RESULT_NOT_EQUAL,
|
||||
|
||||
#ifndef U_HIDE_INTERNAL_API
|
||||
/**
|
||||
* The number of entries in this enum.
|
||||
* @internal
|
||||
*/
|
||||
UNUM_IDENTITY_RESULT_COUNT
|
||||
#endif
|
||||
|
||||
} UNumberRangeIdentityResult;
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
namespace number { // icu::number
|
||||
|
@ -182,6 +61,7 @@ struct RangeMacroProps;
|
|||
class DecimalQuantity;
|
||||
class UFormattedNumberRangeData;
|
||||
class NumberRangeFormatterImpl;
|
||||
struct UFormattedNumberRangeImpl;
|
||||
|
||||
} // namespace impl
|
||||
|
||||
|
@ -418,8 +298,8 @@ class U_I18N_API NumberRangeFormatterSettings {
|
|||
|
||||
/**
|
||||
* Sets the behavior when the two sides of the range are the same. This could happen if the same two numbers are
|
||||
* passed to the formatRange function, or if different numbers are passed to the function but they become the same
|
||||
* after rounding rules are applied. Possible values:
|
||||
* passed to the formatFormattableRange function, or if different numbers are passed to the function but they
|
||||
* become the same after rounding rules are applied. Possible values:
|
||||
* <p>
|
||||
* <ul>
|
||||
* <li>SINGLE_VALUE: "5 miles"</li>
|
||||
|
@ -820,6 +700,9 @@ class U_I18N_API FormattedNumberRange : public UMemory, public FormattedValue {
|
|||
|
||||
// To give LocalizedNumberRangeFormatter format methods access to this class's constructor:
|
||||
friend class LocalizedNumberRangeFormatter;
|
||||
|
||||
// To give C API access to internals
|
||||
friend struct impl::UFormattedNumberRangeImpl;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
// © 2018 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html
|
||||
|
||||
#ifndef __UNUMBERFORMATTER_H__
|
||||
#define __UNUMBERFORMATTER_H__
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
#ifndef __UNUMBERFORMATTER_H__
|
||||
#define __UNUMBERFORMATTER_H__
|
||||
|
||||
#include "unicode/parseerr.h"
|
||||
#include "unicode/ufieldpositer.h"
|
||||
|
@ -725,5 +726,5 @@ U_DEFINE_LOCAL_OPEN_POINTER(LocalUFormattedNumberPointer, UFormattedNumber, unum
|
|||
U_NAMESPACE_END
|
||||
#endif // U_SHOW_CPLUSPLUS_API
|
||||
|
||||
#endif //__UNUMBERFORMATTER_H__
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
#endif //__UNUMBERFORMATTER_H__
|
||||
|
|
432
icu4c/source/i18n/unicode/unumberrangeformatter.h
Normal file
432
icu4c/source/i18n/unicode/unumberrangeformatter.h
Normal file
|
@ -0,0 +1,432 @@
|
|||
// © 2020 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html
|
||||
|
||||
#ifndef __UNUMBERRANGEFORMATTER_H__
|
||||
#define __UNUMBERRANGEFORMATTER_H__
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
#include "unicode/parseerr.h"
|
||||
#include "unicode/ufieldpositer.h"
|
||||
#include "unicode/umisc.h"
|
||||
#include "unicode/uformattedvalue.h"
|
||||
#include "unicode/uformattable.h"
|
||||
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief C-compatible API for localized number range formatting.
|
||||
*
|
||||
* This is the C-compatible version of the NumberRangeFormatter API. C++ users
|
||||
* should include unicode/numberrangeformatter.h and use the proper C++ APIs.
|
||||
*
|
||||
* First create a UNumberRangeFormatter, which is immutable, and then format to
|
||||
* a UFormattedNumberRange.
|
||||
*
|
||||
* Example code:
|
||||
* <pre>
|
||||
* // Setup:
|
||||
* UErrorCode ec = U_ZERO_ERROR;
|
||||
* UNumberRangeFormatter* uformatter = unumrf_openForSkeletonCollapseIdentityFallbackAndLocaleWithError(
|
||||
* u"currency/USD precision-integer",
|
||||
* -1,
|
||||
* UNUM_RANGE_COLLAPSE_AUTO,
|
||||
* UNUM_IDENTITY_FALLBACK_APPROXIMATELY,
|
||||
* "en-US",
|
||||
* NULL,
|
||||
* &ec);
|
||||
* UFormattedNumberRange* uresult = unumrf_openResult(&ec);
|
||||
* if (U_FAILURE(ec)) { return; }
|
||||
*
|
||||
* // Format a double range:
|
||||
* unumrf_formatDoubleRange(uformatter, 3.0, 5.0, uresult, &ec);
|
||||
* if (U_FAILURE(ec)) { return; }
|
||||
*
|
||||
* // Get the result string:
|
||||
* int32_t len;
|
||||
* const UChar* str = ufmtval_getString(unumrf_resultAsValue(uresult, &ec), &len, &ec);
|
||||
* if (U_FAILURE(ec)) { return; }
|
||||
* // str should equal "$3 – $5"
|
||||
*
|
||||
* // Cleanup:
|
||||
* unumf_close(uformatter);
|
||||
* unumf_closeResult(uresult);
|
||||
* </pre>
|
||||
*
|
||||
* If you are a C++ user linking against the C libraries, you can use the LocalPointer versions of these
|
||||
* APIs. The following example uses LocalPointer with the decimal number and field position APIs:
|
||||
*
|
||||
* <pre>
|
||||
* // Setup:
|
||||
* LocalUNumberRangeFormatterPointer uformatter(
|
||||
* unumrf_openForSkeletonCollapseIdentityFallbackAndLocaleWithError(...));
|
||||
* LocalUFormattedNumberRangePointer uresult(unumrf_openResult(&ec));
|
||||
* if (U_FAILURE(ec)) { return; }
|
||||
*
|
||||
* // Format a double number range:
|
||||
* unumrf_formatDoubleRange(uformatter.getAlias(), 3.0, 5.0, uresult.getAlias(), &ec);
|
||||
* if (U_FAILURE(ec)) { return; }
|
||||
*
|
||||
* // No need to do any cleanup since we are using LocalPointer.
|
||||
* </pre>
|
||||
*
|
||||
* You can also get field positions. For more information, see uformattedvalue.h.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Defines how to merge fields that are identical across the range sign.
|
||||
*
|
||||
* @stable ICU 63
|
||||
*/
|
||||
typedef enum UNumberRangeCollapse {
|
||||
/**
|
||||
* Use locale data and heuristics to determine how much of the string to collapse. Could end up collapsing none,
|
||||
* some, or all repeated pieces in a locale-sensitive way.
|
||||
*
|
||||
* The heuristics used for this option are subject to change over time.
|
||||
*
|
||||
* @stable ICU 63
|
||||
*/
|
||||
UNUM_RANGE_COLLAPSE_AUTO,
|
||||
|
||||
/**
|
||||
* Do not collapse any part of the number. Example: "3.2 thousand kilograms – 5.3 thousand kilograms"
|
||||
*
|
||||
* @stable ICU 63
|
||||
*/
|
||||
UNUM_RANGE_COLLAPSE_NONE,
|
||||
|
||||
/**
|
||||
* Collapse the unit part of the number, but not the notation, if present. Example: "3.2 thousand – 5.3 thousand
|
||||
* kilograms"
|
||||
*
|
||||
* @stable ICU 63
|
||||
*/
|
||||
UNUM_RANGE_COLLAPSE_UNIT,
|
||||
|
||||
/**
|
||||
* Collapse any field that is equal across the range sign. May introduce ambiguity on the magnitude of the
|
||||
* number. Example: "3.2 – 5.3 thousand kilograms"
|
||||
*
|
||||
* @stable ICU 63
|
||||
*/
|
||||
UNUM_RANGE_COLLAPSE_ALL
|
||||
} UNumberRangeCollapse;
|
||||
|
||||
/**
|
||||
* Defines the behavior when the two numbers in the range are identical after rounding. To programmatically detect
|
||||
* when the identity fallback is used, compare the lower and upper BigDecimals via FormattedNumber.
|
||||
*
|
||||
* @stable ICU 63
|
||||
* @see NumberRangeFormatter
|
||||
*/
|
||||
typedef enum UNumberRangeIdentityFallback {
|
||||
/**
|
||||
* Show the number as a single value rather than a range. Example: "$5"
|
||||
*
|
||||
* @stable ICU 63
|
||||
*/
|
||||
UNUM_IDENTITY_FALLBACK_SINGLE_VALUE,
|
||||
|
||||
/**
|
||||
* Show the number using a locale-sensitive approximation pattern. If the numbers were the same before rounding,
|
||||
* show the single value. Example: "~$5" or "$5"
|
||||
*
|
||||
* @stable ICU 63
|
||||
*/
|
||||
UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE,
|
||||
|
||||
/**
|
||||
* Show the number using a locale-sensitive approximation pattern. Use the range pattern always, even if the
|
||||
* inputs are the same. Example: "~$5"
|
||||
*
|
||||
* @stable ICU 63
|
||||
*/
|
||||
UNUM_IDENTITY_FALLBACK_APPROXIMATELY,
|
||||
|
||||
/**
|
||||
* Show the number as the range of two equal values. Use the range pattern always, even if the inputs are the
|
||||
* same. Example (with RangeCollapse.NONE): "$5 – $5"
|
||||
*
|
||||
* @stable ICU 63
|
||||
*/
|
||||
UNUM_IDENTITY_FALLBACK_RANGE
|
||||
} UNumberRangeIdentityFallback;
|
||||
|
||||
/**
|
||||
* Used in the result class FormattedNumberRange to indicate to the user whether the numbers formatted in the range
|
||||
* were equal or not, and whether or not the identity fallback was applied.
|
||||
*
|
||||
* @stable ICU 63
|
||||
* @see NumberRangeFormatter
|
||||
*/
|
||||
typedef enum UNumberRangeIdentityResult {
|
||||
/**
|
||||
* Used to indicate that the two numbers in the range were equal, even before any rounding rules were applied.
|
||||
*
|
||||
* @stable ICU 63
|
||||
* @see NumberRangeFormatter
|
||||
*/
|
||||
UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING,
|
||||
|
||||
/**
|
||||
* Used to indicate that the two numbers in the range were equal, but only after rounding rules were applied.
|
||||
*
|
||||
* @stable ICU 63
|
||||
* @see NumberRangeFormatter
|
||||
*/
|
||||
UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING,
|
||||
|
||||
/**
|
||||
* Used to indicate that the two numbers in the range were not equal, even after rounding rules were applied.
|
||||
*
|
||||
* @stable ICU 63
|
||||
* @see NumberRangeFormatter
|
||||
*/
|
||||
UNUM_IDENTITY_RESULT_NOT_EQUAL,
|
||||
|
||||
#ifndef U_HIDE_INTERNAL_API
|
||||
/**
|
||||
* The number of entries in this enum.
|
||||
* @internal
|
||||
*/
|
||||
UNUM_IDENTITY_RESULT_COUNT
|
||||
#endif
|
||||
|
||||
} UNumberRangeIdentityResult;
|
||||
|
||||
|
||||
#ifndef U_HIDE_DRAFT_API
|
||||
|
||||
struct UNumberRangeFormatter;
|
||||
/**
|
||||
* C-compatible version of icu::number::LocalizedNumberRangeFormatter.
|
||||
*
|
||||
* NOTE: This is a C-compatible API; C++ users should build against numberrangeformatter.h instead.
|
||||
*
|
||||
* @draft ICU 68
|
||||
*/
|
||||
typedef struct UNumberRangeFormatter UNumberRangeFormatter;
|
||||
|
||||
|
||||
struct UFormattedNumberRange;
|
||||
/**
|
||||
* C-compatible version of icu::number::FormattedNumberRange.
|
||||
*
|
||||
* NOTE: This is a C-compatible API; C++ users should build against numberrangeformatter.h instead.
|
||||
*
|
||||
* @draft ICU 68
|
||||
*/
|
||||
typedef struct UFormattedNumberRange UFormattedNumberRange;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new UNumberFormatter for the given skeleton string, collapse option, identity fallback
|
||||
* option, and locale. This is currently the only method for creating a new UNumberRangeFormatter.
|
||||
*
|
||||
* Objects of type UNumberRangeFormatter returned by this method are threadsafe.
|
||||
*
|
||||
* For more details on skeleton strings, see the documentation in numberrangeformatter.h. For more
|
||||
* details on the usage of this API, see the documentation at the top of unumberrangeformatter.h.
|
||||
*
|
||||
* NOTE: This is a C-compatible API; C++ users should build against numberrangeformatter.h instead.
|
||||
*
|
||||
* @param skeleton The skeleton string, like u"percent precision-integer"
|
||||
* @param skeletonLen The number of UChars in the skeleton string, or -1 if it is NUL-terminated.
|
||||
* @param collapse Option for how to merge affixes (if unsure, use UNUM_RANGE_COLLAPSE_AUTO)
|
||||
* @param identityFallback Option for resolving when both sides of the range are equal.
|
||||
* @param locale The NUL-terminated locale ID.
|
||||
* @param perror A parse error struct populated if an error occurs when parsing. Can be NULL.
|
||||
* If no error occurs, perror->offset will be set to -1.
|
||||
* @param ec Set if an error occurs.
|
||||
* @draft ICU 68
|
||||
*/
|
||||
U_STABLE UNumberRangeFormatter* U_EXPORT2
|
||||
unumrf_openForSkeletonWithCollapseAndIdentityFallback(
|
||||
const UChar* skeleton,
|
||||
int32_t skeletonLen,
|
||||
UNumberRangeCollapse collapse,
|
||||
UNumberRangeIdentityFallback identityFallback,
|
||||
const char* locale,
|
||||
UParseError* perror,
|
||||
UErrorCode* ec);
|
||||
|
||||
|
||||
/**
|
||||
* Creates an object to hold the result of a UNumberRangeFormatter
|
||||
* operation. The object can be used repeatedly; it is cleared whenever
|
||||
* passed to a format function.
|
||||
*
|
||||
* @param ec Set if an error occurs.
|
||||
* @draft ICU 68
|
||||
*/
|
||||
U_STABLE UFormattedNumberRange* U_EXPORT2
|
||||
unumrf_openResult(UErrorCode* ec);
|
||||
|
||||
|
||||
/**
|
||||
* Uses a UNumberRangeFormatter to format a range of doubles.
|
||||
*
|
||||
* The UNumberRangeFormatter can be shared between threads. Each thread should have its own local
|
||||
* UFormattedNumberRange, however, for storing the result of the formatting operation.
|
||||
*
|
||||
* NOTE: This is a C-compatible API; C++ users should build against numberrangeformatter.h instead.
|
||||
*
|
||||
* @param uformatter A formatter object; see unumberrangeformatter.h.
|
||||
* @param first The first (usually smaller) number in the range.
|
||||
* @param second The second (usually larger) number in the range.
|
||||
* @param uresult The object that will be mutated to store the result; see unumrf_openResult.
|
||||
* @param ec Set if an error occurs.
|
||||
* @draft ICU 68
|
||||
*/
|
||||
U_STABLE void U_EXPORT2
|
||||
unumrf_formatDoubleRange(
|
||||
const UNumberRangeFormatter* uformatter,
|
||||
double first,
|
||||
double second,
|
||||
UFormattedNumberRange* uresult,
|
||||
UErrorCode* ec);
|
||||
|
||||
|
||||
/**
|
||||
* Uses a UNumberRangeFormatter to format a range of decimal numbers.
|
||||
*
|
||||
* With a decimal number string, you can specify an input with arbitrary precision.
|
||||
*
|
||||
* The UNumberRangeFormatter can be shared between threads. Each thread should have its own local
|
||||
* UFormattedNumberRange, however, for storing the result of the formatting operation.
|
||||
*
|
||||
* NOTE: This is a C-compatible API; C++ users should build against numberrangeformatter.h instead.
|
||||
*
|
||||
* @param uformatter A formatter object; see unumberrangeformatter.h.
|
||||
* @param first The first (usually smaller) number in the range.
|
||||
* @param firstLen The length of the first decimal number string.
|
||||
* @param second The second (usually larger) number in the range.
|
||||
* @param secondLen The length of the second decimal number string.
|
||||
* @param uresult The object that will be mutated to store the result; see unumrf_openResult.
|
||||
* @param ec Set if an error occurs.
|
||||
* @draft ICU 68
|
||||
*/
|
||||
U_STABLE void U_EXPORT2
|
||||
unumrf_formatDecimalRange(
|
||||
const UNumberRangeFormatter* uformatter,
|
||||
const char* first,
|
||||
int32_t firstLen,
|
||||
const char* second,
|
||||
int32_t secondLen,
|
||||
UFormattedNumberRange* uresult,
|
||||
UErrorCode* ec);
|
||||
|
||||
|
||||
/**
|
||||
* Returns a representation of a UFormattedNumberRange as a UFormattedValue,
|
||||
* which can be subsequently passed to any API requiring that type.
|
||||
*
|
||||
* The returned object is owned by the UFormattedNumberRange and is valid
|
||||
* only as long as the UFormattedNumber is present and unchanged in memory.
|
||||
*
|
||||
* You can think of this method as a cast between types.
|
||||
*
|
||||
* @param uresult The object containing the formatted number range.
|
||||
* @param ec Set if an error occurs.
|
||||
* @return A UFormattedValue owned by the input object.
|
||||
* @draft ICU 68
|
||||
*/
|
||||
U_STABLE const UFormattedValue* U_EXPORT2
|
||||
unumrf_resultAsValue(const UFormattedNumberRange* uresult, UErrorCode* ec);
|
||||
|
||||
|
||||
/**
|
||||
* Extracts the identity result from a UFormattedNumberRange.
|
||||
*
|
||||
* NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead.
|
||||
*
|
||||
* @param uresult The object containing the formatted number range.
|
||||
* @param ec Set if an error occurs.
|
||||
* @return The identity result; see UNumberRangeIdentityResult.
|
||||
* @draft ICU 68
|
||||
*/
|
||||
U_STABLE UNumberRangeIdentityResult U_EXPORT2
|
||||
unumrf_resultGetIdentityResult(
|
||||
const UFormattedNumberRange* uresult,
|
||||
UErrorCode* ec);
|
||||
|
||||
|
||||
|
||||
// TODO(ICU-20775): Propose these as API.
|
||||
// NOTE: This is not currently implemented.
|
||||
// U_DRAFT int32_t U_EXPORT2
|
||||
// unumf_resultGetFirstDecimal(const UFormattedNumberRange* uresult, char* buffer, int32_t bufferCapacity,
|
||||
// UErrorCode* ec);
|
||||
// U_DRAFT int32_t U_EXPORT2
|
||||
// unumf_resultGetSecondDecimal(const UFormattedNumberRange* uresult, char* buffer, int32_t bufferCapacity,
|
||||
// UErrorCode* ec);
|
||||
|
||||
|
||||
/**
|
||||
* Releases the UNumberFormatter created by unumf_openForSkeletonAndLocale().
|
||||
*
|
||||
* @param uformatter An object created by unumf_openForSkeletonAndLocale().
|
||||
* @draft ICU 68
|
||||
*/
|
||||
U_STABLE void U_EXPORT2
|
||||
unumrf_close(UNumberRangeFormatter* uformatter);
|
||||
|
||||
|
||||
/**
|
||||
* Releases the UFormattedNumber created by unumf_openResult().
|
||||
*
|
||||
* @param uresult An object created by unumf_openResult().
|
||||
* @draft ICU 68
|
||||
*/
|
||||
U_STABLE void U_EXPORT2
|
||||
unumrf_closeResult(UFormattedNumberRange* uresult);
|
||||
|
||||
|
||||
#if U_SHOW_CPLUSPLUS_API
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
/**
|
||||
* \class LocalUNumberRangeFormatterPointer
|
||||
* "Smart pointer" class; closes a UNumberFormatter via unumf_close().
|
||||
* For most methods see the LocalPointerBase base class.
|
||||
*
|
||||
* Usage:
|
||||
* <pre>
|
||||
* LocalUNumberRangeFormatterPointer uformatter(
|
||||
* unumrf_openForSkeletonCollapseIdentityFallbackAndLocaleWithError(...));
|
||||
* // no need to explicitly call unumrf_close()
|
||||
* </pre>
|
||||
*
|
||||
* @see LocalPointerBase
|
||||
* @see LocalPointer
|
||||
* @draft ICU 68
|
||||
*/
|
||||
U_DEFINE_LOCAL_OPEN_POINTER(LocalUNumberRangeFormatterPointer, UNumberRangeFormatter, unumrf_close);
|
||||
|
||||
/**
|
||||
* \class LocalUFormattedNumberPointer
|
||||
* "Smart pointer" class; closes a UFormattedNumber via unumf_closeResult().
|
||||
* For most methods see the LocalPointerBase base class.
|
||||
*
|
||||
* Usage:
|
||||
* <pre>
|
||||
* LocalUFormattedNumberRangePointer uresult(unumrf_openResult(...));
|
||||
* // no need to explicitly call unumrf_closeResult()
|
||||
* </pre>
|
||||
*
|
||||
* @see LocalPointerBase
|
||||
* @see LocalPointer
|
||||
* @draft ICU 68
|
||||
*/
|
||||
U_DEFINE_LOCAL_OPEN_POINTER(LocalUFormattedNumberRangePointer, UFormattedNumberRange, unumrf_closeResult);
|
||||
|
||||
U_NAMESPACE_END
|
||||
#endif // U_SHOW_CPLUSPLUS_API
|
||||
|
||||
#endif // U_HIDE_DRAFT_API
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
#endif //__UNUMBERRANGEFORMATTER_H__
|
|
@ -55,7 +55,7 @@ hpmufn.o tracetst.o reapits.o uregiontest.o ulistfmttest.o\
|
|||
utexttst.o ucsdetst.o spooftest.o \
|
||||
cbiditransformtst.o \
|
||||
cgendtst.o \
|
||||
unumberformattertst.o uformattedvaluetst.o
|
||||
unumberformattertst.o uformattedvaluetst.o unumberrangeformattertst.o
|
||||
|
||||
DEPS = $(OBJECTS:.o=.d)
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ void addURegionTest(TestNode** root);
|
|||
void addUListFmtTest(TestNode** root);
|
||||
void addUNumberFormatterTest(TestNode** root);
|
||||
void addUFormattedValueTest(TestNode** root);
|
||||
void addUNumberRangeFormatterTest(TestNode** root);
|
||||
|
||||
void addFormatTest(TestNode** root);
|
||||
|
||||
|
@ -65,6 +66,7 @@ void addFormatTest(TestNode** root)
|
|||
addUListFmtTest(root);
|
||||
addUNumberFormatterTest(root);
|
||||
addUFormattedValueTest(root);
|
||||
addUNumberRangeFormatterTest(root);
|
||||
}
|
||||
/*Internal functions used*/
|
||||
|
||||
|
|
|
@ -175,6 +175,7 @@
|
|||
<ClCompile Include="ulistfmttest.c" />
|
||||
<ClCompile Include="unumberformattertst.c" />
|
||||
<ClCompile Include="uformattedvaluetst.c" />
|
||||
<ClCompile Include="unumberrangeformattertst.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="cbiditst.h" />
|
||||
|
|
|
@ -225,6 +225,9 @@
|
|||
<ClInclude Include="uformattedvaluetst.c">
|
||||
<Filter>formatting</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="unumberrangeformattertst.c">
|
||||
<Filter>formatting</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="cldrtest.c">
|
||||
<Filter>locales & resources</Filter>
|
||||
</ClCompile>
|
||||
|
|
152
icu4c/source/test/cintltst/unumberrangeformattertst.c
Normal file
152
icu4c/source/test/cintltst/unumberrangeformattertst.c
Normal file
|
@ -0,0 +1,152 @@
|
|||
// © 2018 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
// Allow implicit conversion from char16_t* to UnicodeString for this file:
|
||||
// Helpful in toString methods and elsewhere.
|
||||
#define UNISTR_FROM_STRING_EXPLICIT
|
||||
|
||||
#include <stdio.h>
|
||||
#include "unicode/unumberformatter.h"
|
||||
#include "unicode/unumberrangeformatter.h"
|
||||
#include "unicode/umisc.h"
|
||||
#include "unicode/unum.h"
|
||||
#include "unicode/ustring.h"
|
||||
#include "cformtst.h"
|
||||
#include "cintltst.h"
|
||||
#include "cmemory.h"
|
||||
|
||||
static void TestExampleCode(void);
|
||||
|
||||
static void TestFormattedValue(void);
|
||||
|
||||
static void TestSkeletonParseError(void);
|
||||
|
||||
void addUNumberRangeFormatterTest(TestNode** root);
|
||||
|
||||
#define TESTCASE(x) addTest(root, &x, "tsformat/unumberrangeformatter/" #x)
|
||||
|
||||
void addUNumberRangeFormatterTest(TestNode** root) {
|
||||
TESTCASE(TestExampleCode);
|
||||
TESTCASE(TestFormattedValue);
|
||||
TESTCASE(TestSkeletonParseError);
|
||||
}
|
||||
|
||||
|
||||
static void TestExampleCode() {
|
||||
// This is the example code given in unumberrangeformatter.h.
|
||||
|
||||
// Setup:
|
||||
UErrorCode ec = U_ZERO_ERROR;
|
||||
UNumberRangeFormatter* uformatter = unumrf_openForSkeletonWithCollapseAndIdentityFallback(
|
||||
u"currency/USD precision-integer",
|
||||
-1,
|
||||
UNUM_RANGE_COLLAPSE_AUTO,
|
||||
UNUM_IDENTITY_FALLBACK_APPROXIMATELY,
|
||||
"en-US",
|
||||
NULL,
|
||||
&ec);
|
||||
UFormattedNumberRange* uresult = unumrf_openResult(&ec);
|
||||
assertSuccessCheck("There should not be a failure in the example code", &ec, TRUE);
|
||||
|
||||
// Format a double range:
|
||||
unumrf_formatDoubleRange(uformatter, 3.0, 5.0, uresult, &ec);
|
||||
assertSuccessCheck("There should not be a failure in the example code", &ec, TRUE);
|
||||
|
||||
// Get the result string:
|
||||
int32_t len;
|
||||
const UChar* str = ufmtval_getString(unumrf_resultAsValue(uresult, &ec), &len, &ec);
|
||||
assertSuccessCheck("There should not be a failure in the example code", &ec, TRUE);
|
||||
assertUEquals("Should produce expected string result", u"$3 – $5", str);
|
||||
|
||||
// Cleanup:
|
||||
unumrf_close(uformatter);
|
||||
unumrf_closeResult(uresult);
|
||||
}
|
||||
|
||||
|
||||
static void TestFormattedValue() {
|
||||
UErrorCode ec = U_ZERO_ERROR;
|
||||
UNumberRangeFormatter* uformatter = unumrf_openForSkeletonWithCollapseAndIdentityFallback(
|
||||
u"K",
|
||||
-1,
|
||||
UNUM_RANGE_COLLAPSE_AUTO,
|
||||
UNUM_IDENTITY_FALLBACK_APPROXIMATELY,
|
||||
"en-US",
|
||||
NULL,
|
||||
&ec);
|
||||
assertSuccessCheck("Should create without error", &ec, TRUE);
|
||||
UFormattedNumberRange* uresult = unumrf_openResult(&ec);
|
||||
assertSuccess("Should create result without error", &ec);
|
||||
|
||||
// Test the decimal number code path, too
|
||||
unumrf_formatDecimalRange(uformatter, "5.5e4", -1, "1.5e5", -1, uresult, &ec);
|
||||
|
||||
if (assertSuccessCheck("Should format without error", &ec, TRUE)) {
|
||||
const UFormattedValue* fv = unumrf_resultAsValue(uresult, &ec);
|
||||
assertSuccess("Should convert without error", &ec);
|
||||
static const UFieldPosition expectedFieldPositions[] = {
|
||||
// field, begin index, end index
|
||||
{UNUM_INTEGER_FIELD, 0, 2},
|
||||
{UNUM_COMPACT_FIELD, 2, 3},
|
||||
{UNUM_INTEGER_FIELD, 6, 9},
|
||||
{UNUM_COMPACT_FIELD, 9, 10}};
|
||||
checkFormattedValue(
|
||||
"FormattedNumber as FormattedValue",
|
||||
fv,
|
||||
u"55K – 150K",
|
||||
UFIELD_CATEGORY_NUMBER,
|
||||
expectedFieldPositions,
|
||||
UPRV_LENGTHOF(expectedFieldPositions));
|
||||
}
|
||||
|
||||
assertIntEquals("Identity result should match",
|
||||
UNUM_IDENTITY_RESULT_NOT_EQUAL,
|
||||
unumrf_resultGetIdentityResult(uresult, &ec));
|
||||
|
||||
// cleanup:
|
||||
unumrf_closeResult(uresult);
|
||||
unumrf_close(uformatter);
|
||||
}
|
||||
|
||||
|
||||
static void TestSkeletonParseError() {
|
||||
UErrorCode ec = U_ZERO_ERROR;
|
||||
UNumberRangeFormatter* uformatter;
|
||||
UParseError perror;
|
||||
|
||||
// The UParseError can be null. The following should not segfault.
|
||||
uformatter = unumrf_openForSkeletonWithCollapseAndIdentityFallback(
|
||||
u".00 measure-unit/typo",
|
||||
-1,
|
||||
UNUM_RANGE_COLLAPSE_AUTO,
|
||||
UNUM_IDENTITY_FALLBACK_APPROXIMATELY,
|
||||
"en",
|
||||
NULL,
|
||||
&ec);
|
||||
unumrf_close(uformatter);
|
||||
|
||||
// Now test the behavior.
|
||||
ec = U_ZERO_ERROR;
|
||||
uformatter = unumrf_openForSkeletonWithCollapseAndIdentityFallback(
|
||||
u".00 measure-unit/typo",
|
||||
-1,
|
||||
UNUM_RANGE_COLLAPSE_AUTO,
|
||||
UNUM_IDENTITY_FALLBACK_APPROXIMATELY,
|
||||
"en",
|
||||
&perror,
|
||||
&ec);
|
||||
|
||||
assertIntEquals("Should have set error code", U_NUMBER_SKELETON_SYNTAX_ERROR, ec);
|
||||
assertIntEquals("Should have correct skeleton error offset", 17, perror.offset);
|
||||
assertUEquals("Should have correct pre context", u"0 measure-unit/", perror.preContext);
|
||||
assertUEquals("Should have correct post context", u"typo", perror.postContext);
|
||||
|
||||
// cleanup:
|
||||
unumrf_close(uformatter);
|
||||
}
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
|
@ -1000,7 +1000,7 @@ group: numberformatter
|
|||
|
||||
group: number_skeletons
|
||||
# Number skeleton support; separated from numberformatter
|
||||
number_skeletons.o number_capi.o number_asformat.o
|
||||
number_skeletons.o number_capi.o number_asformat.o numrange_capi.o
|
||||
deps
|
||||
numberformatter
|
||||
units_extra
|
||||
|
|
Loading…
Add table
Reference in a new issue