ICU-12684 Add unum_formatDoubleForFields and test
X-SVN-Rev: 39565
This commit is contained in:
parent
26d15e5eca
commit
32ca386c27
@ -25,6 +25,7 @@
|
||||
#include "unicode/parseerr.h"
|
||||
#include "unicode/uformattable.h"
|
||||
#include "unicode/udisplaycontext.h"
|
||||
#include "unicode/ufieldpositer.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
@ -553,6 +554,59 @@ unum_formatDouble( const UNumberFormat* fmt,
|
||||
UFieldPosition *pos, /* 0 if ignore */
|
||||
UErrorCode* status);
|
||||
|
||||
#ifndef U_HIDE_DRAFT_API
|
||||
/**
|
||||
* Format a double using a UNumberFormat according to the UNumberFormat's locale,
|
||||
* and initialize a UFieldPositionIterator that enumerates the subcomponents of
|
||||
* the resulting string.
|
||||
*
|
||||
* @param format
|
||||
* The formatter to use.
|
||||
* @param number
|
||||
* The number to format.
|
||||
* @param result
|
||||
* A pointer to a buffer to receive the NULL-terminated formatted
|
||||
* number. If the formatted number fits into dest but cannot be
|
||||
* NULL-terminated (length == resultLength) then the error code is set
|
||||
* to U_STRING_NOT_TERMINATED_WARNING. If the formatted number doesn't
|
||||
* fit into result then the error code is set to
|
||||
* U_BUFFER_OVERFLOW_ERROR.
|
||||
* @param resultLength
|
||||
* The maximum size of result.
|
||||
* @param fpositer
|
||||
* A pointer to a UFieldPositionIterator created by {@link #ufieldpositer_open}
|
||||
* (may be NULL if field position information is not needed, but in this
|
||||
* case it's preferable to use {@link #unum_formatDouble}). Iteration
|
||||
* information already present in the UFieldPositionIterator is deleted,
|
||||
* and the iterator is reset to apply to the fields in the formatted
|
||||
* string created by this function call. The field values and indexes
|
||||
* returned by {@link #ufieldpositer_next} represent fields denoted by
|
||||
* the UNumberFormatFields enum. Fields are not returned in a guaranteed
|
||||
* order. Fields cannot overlap, but they may nest. For example, 1234
|
||||
* could format as "1,234" which might consist of a grouping separator
|
||||
* field for ',' and an integer field encompassing the entire string.
|
||||
* @param status
|
||||
* A pointer to an UErrorCode to receive any errors
|
||||
* @return
|
||||
* The total buffer size needed; if greater than resultLength, the
|
||||
* output was truncated.
|
||||
* @see unum_formatDouble
|
||||
* @see unum_parse
|
||||
* @see unum_parseDouble
|
||||
* @see UFieldPositionIterator
|
||||
* @see UNumberFormatFields
|
||||
* @draft ICU 59
|
||||
*/
|
||||
U_DRAFT int32_t U_EXPORT2
|
||||
unum_formatDoubleForFields(const UNumberFormat* format,
|
||||
double number,
|
||||
UChar* result,
|
||||
int32_t resultLength,
|
||||
UFieldPositionIterator* fpositer,
|
||||
UErrorCode* status);
|
||||
|
||||
#endif /* U_HIDE_DRAFT_API */
|
||||
|
||||
/**
|
||||
* Format a decimal number using a UNumberFormat.
|
||||
* The number will be formatted according to the UNumberFormat's locale.
|
||||
|
@ -247,6 +247,33 @@ unum_formatDouble( const UNumberFormat* fmt,
|
||||
return res.extract(result, resultLength, *status);
|
||||
}
|
||||
|
||||
U_CAPI int32_t U_EXPORT2
|
||||
unum_formatDoubleForFields(const UNumberFormat* format,
|
||||
double number,
|
||||
UChar* result,
|
||||
int32_t resultLength,
|
||||
UFieldPositionIterator* fpositer,
|
||||
UErrorCode* status)
|
||||
{
|
||||
if (U_FAILURE(*status))
|
||||
return -1;
|
||||
|
||||
if (result == NULL ? resultLength != 0 : resultLength < 0) {
|
||||
*status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
UnicodeString res;
|
||||
if (result != NULL) {
|
||||
// NULL destination for pure preflighting: empty dummy string
|
||||
// otherwise, alias the destination buffer
|
||||
res.setTo(result, 0, resultLength);
|
||||
}
|
||||
|
||||
((const NumberFormat*)format)->format(number, res, (FieldPositionIterator*)fpositer, *status);
|
||||
|
||||
return res.extract(result, resultLength, *status);
|
||||
}
|
||||
|
||||
U_CAPI int32_t U_EXPORT2
|
||||
unum_formatDecimal(const UNumberFormat* fmt,
|
||||
|
@ -63,6 +63,7 @@ static void TestCurrencyUsage(void);
|
||||
static void TestCurrFmtNegSameAsPositive(void);
|
||||
static void TestVariousStylesAndAttributes(void);
|
||||
static void TestParseCurrPatternWithDecStyle(void);
|
||||
static void TestFormatForFields(void);
|
||||
|
||||
#define TESTCASE(x) addTest(root, &x, "tsformat/cnumtst/" #x)
|
||||
|
||||
@ -93,6 +94,7 @@ void addNumForTest(TestNode** root)
|
||||
TESTCASE(TestCurrFmtNegSameAsPositive);
|
||||
TESTCASE(TestVariousStylesAndAttributes);
|
||||
TESTCASE(TestParseCurrPatternWithDecStyle);
|
||||
TESTCASE(TestFormatForFields);
|
||||
}
|
||||
|
||||
/* test Parse int 64 */
|
||||
@ -2887,4 +2889,111 @@ static void TestParseCurrPatternWithDecStyle() {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Ticket #12684
|
||||
* Test unum_formatDoubleForFields (and UFieldPositionIterator)
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
int32_t field;
|
||||
int32_t beginPos;
|
||||
int32_t endPos;
|
||||
} FieldsData;
|
||||
|
||||
typedef struct {
|
||||
const char * locale;
|
||||
UNumberFormatStyle style;
|
||||
double value;
|
||||
const FieldsData * expectedFields;
|
||||
} FormatForFieldsItem;
|
||||
|
||||
static const UChar patNoFields[] = { 0x0027, 0x0078, 0x0027, 0 }; /* "'x'", for UNUM_PATTERN_DECIMAL */
|
||||
|
||||
|
||||
/* "en_US", UNUM_CURRENCY, 123456.0 : "¤#,##0.00" => "$123,456.00" */
|
||||
static const FieldsData fields_en_CURR[] = {
|
||||
{ UNUM_CURRENCY_FIELD /*7*/, 0, 1 },
|
||||
{ UNUM_GROUPING_SEPARATOR_FIELD /*6*/, 4, 5 },
|
||||
{ UNUM_INTEGER_FIELD /*0*/, 1, 8 },
|
||||
{ UNUM_DECIMAL_SEPARATOR_FIELD /*2*/, 8, 9 },
|
||||
{ UNUM_FRACTION_FIELD /*1*/, 9, 11 },
|
||||
{ -1, -1, -1 },
|
||||
};
|
||||
/* "en_US", UNUM_PERCENT, -34 : "#,##0%" => "-34%" */
|
||||
static const FieldsData fields_en_PRCT[] = {
|
||||
{ UNUM_SIGN_FIELD /*10*/, 0, 1 },
|
||||
{ UNUM_INTEGER_FIELD /*0*/, 1, 3 },
|
||||
{ UNUM_PERCENT_FIELD /*8*/, 3, 4 },
|
||||
{ -1, -1, -1 },
|
||||
};
|
||||
/* "fr_FR", UNUM_CURRENCY, 123456.0 : "#,##0.00 ¤" => "123,456.00 €" */
|
||||
static const FieldsData fields_fr_CURR[] = {
|
||||
{ UNUM_GROUPING_SEPARATOR_FIELD /*6*/, 3, 4 },
|
||||
{ UNUM_INTEGER_FIELD /*0*/, 0, 7 },
|
||||
{ UNUM_DECIMAL_SEPARATOR_FIELD /*2*/, 7, 8 },
|
||||
{ UNUM_FRACTION_FIELD /*1*/, 8, 10 },
|
||||
{ UNUM_CURRENCY_FIELD /*7*/, 11, 12 },
|
||||
{ -1, -1, -1 },
|
||||
};
|
||||
/* "en_US", UNUM_PATTERN_DECIMAL, 12.0 : "'x'" => "x12" */
|
||||
static const FieldsData fields_en_PATN[] = {
|
||||
{ UNUM_INTEGER_FIELD /*0*/, 1, 3 },
|
||||
{ -1, -1, -1 },
|
||||
};
|
||||
|
||||
static const FormatForFieldsItem fffItems[] = {
|
||||
{ "en_US", UNUM_CURRENCY_STANDARD, 123456.0, fields_en_CURR },
|
||||
{ "en_US", UNUM_PERCENT, -0.34, fields_en_PRCT },
|
||||
{ "fr_FR", UNUM_CURRENCY_STANDARD, 123456.0, fields_fr_CURR },
|
||||
{ "en_US", UNUM_PATTERN_DECIMAL, 12.0, fields_en_PATN },
|
||||
{ NULL, (UNumberFormatStyle)0, 0, NULL },
|
||||
};
|
||||
|
||||
static void TestFormatForFields(void) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
UFieldPositionIterator* fpositer = ufieldpositer_open(&status);
|
||||
if ( U_FAILURE(status) ) {
|
||||
log_err("ufieldpositer_open fails, status %s\n", u_errorName(status));
|
||||
} else {
|
||||
const FormatForFieldsItem * itemPtr;
|
||||
for (itemPtr = fffItems; itemPtr->locale != NULL; itemPtr++) {
|
||||
UNumberFormat* unum;
|
||||
status = U_ZERO_ERROR;
|
||||
unum = (itemPtr->style == UNUM_PATTERN_DECIMAL)?
|
||||
unum_open(itemPtr->style, patNoFields, -1, itemPtr->locale, NULL, &status):
|
||||
unum_open(itemPtr->style, NULL, 0, itemPtr->locale, NULL, &status);
|
||||
if ( U_FAILURE(status) ) {
|
||||
log_data_err("unum_open fails for locale %s, style %d: status %s (Are you missing data?)\n", itemPtr->locale, itemPtr->style, u_errorName(status));
|
||||
} else {
|
||||
UChar ubuf[kUBufSize];
|
||||
int32_t ulen = unum_formatDoubleForFields(unum, itemPtr->value, ubuf, kUBufSize, fpositer, &status);
|
||||
if ( U_FAILURE(status) ) {
|
||||
log_err("unum_formatDoubleForFields fails for locale %s, style %d: status %s\n", itemPtr->locale, itemPtr->style, u_errorName(status));
|
||||
} else {
|
||||
const FieldsData * fptr;
|
||||
int32_t field, beginPos, endPos;
|
||||
for (fptr = itemPtr->expectedFields; TRUE; fptr++) {
|
||||
field = ufieldpositer_next(fpositer, &beginPos, &endPos);
|
||||
if (field != fptr->field || (field >= 0 && (beginPos != fptr->beginPos || endPos != fptr->endPos))) {
|
||||
if (fptr->field >= 0) {
|
||||
log_err("unum_formatDoubleForFields for locale %s as \"%s\"; expect field %d range %d-%d, get field %d range %d-%d\n",
|
||||
itemPtr->locale, aescstrdup(ubuf, ulen), fptr->field, fptr->beginPos, fptr->endPos, field, beginPos, endPos);
|
||||
} else {
|
||||
log_err("unum_formatDoubleForFields for locale %s as \"%s\"; expect field < 0, get field %d range %d-%d\n",
|
||||
itemPtr->locale, aescstrdup(ubuf, ulen), field, beginPos, endPos);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (field < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
unum_close(unum);
|
||||
}
|
||||
}
|
||||
ufieldpositer_close(fpositer);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
Loading…
Reference in New Issue
Block a user