mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-10 07:39:16 +00:00
ICU-13763 Makes FieldPositionIterator offset by input string length in DecimalFormat, restoring ICU 61 behavior.
X-SVN-Rev: 41442
This commit is contained in:
parent
49960567e6
commit
2af33b7796
13 changed files with 89 additions and 82 deletions
|
@ -453,9 +453,7 @@ DecimalFormat::format(double number, UnicodeString& appendTo, FieldPositionItera
|
|||
return appendTo;
|
||||
}
|
||||
FormattedNumber output = fields->formatter->formatDouble(number, status);
|
||||
if (posIter != nullptr) {
|
||||
output.populateFieldPositionIterator(*posIter, status);
|
||||
}
|
||||
fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
|
||||
auto appendable = UnicodeStringAppendable(appendTo);
|
||||
output.appendTo(appendable);
|
||||
return appendTo;
|
||||
|
@ -507,9 +505,7 @@ DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPositionIter
|
|||
return appendTo;
|
||||
}
|
||||
FormattedNumber output = fields->formatter->formatInt(number, status);
|
||||
if (posIter != nullptr) {
|
||||
output.populateFieldPositionIterator(*posIter, status);
|
||||
}
|
||||
fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
|
||||
auto appendable = UnicodeStringAppendable(appendTo);
|
||||
output.appendTo(appendable);
|
||||
return appendTo;
|
||||
|
@ -519,9 +515,7 @@ UnicodeString&
|
|||
DecimalFormat::format(StringPiece number, UnicodeString& appendTo, FieldPositionIterator* posIter,
|
||||
UErrorCode& status) const {
|
||||
FormattedNumber output = fields->formatter->formatDecimal(number, status);
|
||||
if (posIter != nullptr) {
|
||||
output.populateFieldPositionIterator(*posIter, status);
|
||||
}
|
||||
fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
|
||||
auto appendable = UnicodeStringAppendable(appendTo);
|
||||
output.appendTo(appendable);
|
||||
return appendTo;
|
||||
|
@ -530,9 +524,7 @@ DecimalFormat::format(StringPiece number, UnicodeString& appendTo, FieldPosition
|
|||
UnicodeString& DecimalFormat::format(const DecimalQuantity& number, UnicodeString& appendTo,
|
||||
FieldPositionIterator* posIter, UErrorCode& status) const {
|
||||
FormattedNumber output = fields->formatter->formatDecimalQuantity(number, status);
|
||||
if (posIter != nullptr) {
|
||||
output.populateFieldPositionIterator(*posIter, status);
|
||||
}
|
||||
fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
|
||||
auto appendable = UnicodeStringAppendable(appendTo);
|
||||
output.appendTo(appendable);
|
||||
return appendTo;
|
||||
|
@ -1237,8 +1229,18 @@ DecimalFormat::fieldPositionHelper(const number::FormattedNumber& formatted, Fie
|
|||
fieldPosition.setEndIndex(0);
|
||||
bool found = formatted.nextFieldPosition(fieldPosition, status);
|
||||
if (found && offset != 0) {
|
||||
fieldPosition.setBeginIndex(fieldPosition.getBeginIndex() + offset);
|
||||
fieldPosition.setEndIndex(fieldPosition.getEndIndex() + offset);
|
||||
FieldPositionOnlyHandler fpoh(fieldPosition);
|
||||
fpoh.shiftLast(offset);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DecimalFormat::fieldPositionIteratorHelper(const number::FormattedNumber& formatted, FieldPositionIterator* fpi,
|
||||
int32_t offset, UErrorCode& status) {
|
||||
if (fpi != nullptr) {
|
||||
FieldPositionIteratorHandler fpih(fpi, status);
|
||||
fpih.setShift(offset);
|
||||
formatted.getAllFieldPositionsImpl(fpih, status);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,17 +22,8 @@ U_NAMESPACE_BEGIN
|
|||
FieldPositionHandler::~FieldPositionHandler() {
|
||||
}
|
||||
|
||||
void
|
||||
FieldPositionHandler::addAttribute(int32_t, int32_t, int32_t) {
|
||||
}
|
||||
|
||||
void
|
||||
FieldPositionHandler::shiftLast(int32_t) {
|
||||
}
|
||||
|
||||
UBool
|
||||
FieldPositionHandler::isRecording(void) const {
|
||||
return FALSE;
|
||||
void FieldPositionHandler::setShift(int32_t delta) {
|
||||
fShift = delta;
|
||||
}
|
||||
|
||||
|
||||
|
@ -48,8 +39,8 @@ FieldPositionOnlyHandler::~FieldPositionOnlyHandler() {
|
|||
void
|
||||
FieldPositionOnlyHandler::addAttribute(int32_t id, int32_t start, int32_t limit) {
|
||||
if (pos.getField() == id) {
|
||||
pos.setBeginIndex(start);
|
||||
pos.setEndIndex(limit);
|
||||
pos.setBeginIndex(start + fShift);
|
||||
pos.setEndIndex(limit + fShift);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,8 +82,8 @@ FieldPositionIteratorHandler::addAttribute(int32_t id, int32_t start, int32_t li
|
|||
if (iter && U_SUCCESS(status) && start < limit) {
|
||||
int32_t size = vec->size();
|
||||
vec->addElement(id, status);
|
||||
vec->addElement(start, status);
|
||||
vec->addElement(limit, status);
|
||||
vec->addElement(start + fShift, status);
|
||||
vec->addElement(limit + fShift, status);
|
||||
if (!U_SUCCESS(status)) {
|
||||
vec->setSize(size);
|
||||
}
|
||||
|
|
|
@ -22,11 +22,16 @@ U_NAMESPACE_BEGIN
|
|||
// base class, null implementation
|
||||
|
||||
class U_I18N_API FieldPositionHandler: public UMemory {
|
||||
protected:
|
||||
int32_t fShift = 0;
|
||||
|
||||
public:
|
||||
virtual ~FieldPositionHandler();
|
||||
virtual void addAttribute(int32_t id, int32_t start, int32_t limit);
|
||||
virtual void shiftLast(int32_t delta);
|
||||
virtual UBool isRecording(void) const;
|
||||
virtual void addAttribute(int32_t id, int32_t start, int32_t limit) = 0;
|
||||
virtual void shiftLast(int32_t delta) = 0;
|
||||
virtual UBool isRecording(void) const = 0;
|
||||
|
||||
void setShift(int32_t delta);
|
||||
};
|
||||
|
||||
|
||||
|
@ -39,9 +44,9 @@ class FieldPositionOnlyHandler : public FieldPositionHandler {
|
|||
FieldPositionOnlyHandler(FieldPosition& pos);
|
||||
virtual ~FieldPositionOnlyHandler();
|
||||
|
||||
virtual void addAttribute(int32_t id, int32_t start, int32_t limit);
|
||||
virtual void shiftLast(int32_t delta);
|
||||
virtual UBool isRecording(void) const;
|
||||
void addAttribute(int32_t id, int32_t start, int32_t limit) U_OVERRIDE;
|
||||
void shiftLast(int32_t delta) U_OVERRIDE;
|
||||
UBool isRecording(void) const U_OVERRIDE;
|
||||
};
|
||||
|
||||
|
||||
|
@ -63,9 +68,9 @@ class FieldPositionIteratorHandler : public FieldPositionHandler {
|
|||
FieldPositionIteratorHandler(FieldPositionIterator* posIter, UErrorCode& status);
|
||||
~FieldPositionIteratorHandler();
|
||||
|
||||
virtual void addAttribute(int32_t id, int32_t start, int32_t limit);
|
||||
virtual void shiftLast(int32_t delta);
|
||||
virtual UBool isRecording(void) const;
|
||||
void addAttribute(int32_t id, int32_t start, int32_t limit) U_OVERRIDE;
|
||||
void shiftLast(int32_t delta) U_OVERRIDE;
|
||||
UBool isRecording(void) const U_OVERRIDE;
|
||||
};
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// Helpful in toString methods and elsewhere.
|
||||
#define UNISTR_FROM_STRING_EXPLICIT
|
||||
|
||||
#include "fphdlimp.h"
|
||||
#include "number_utypes.h"
|
||||
#include "numparse_types.h"
|
||||
#include "unicode/numberformatter.h"
|
||||
|
@ -189,8 +190,9 @@ unumf_resultGetAllFieldPositions(const UFormattedNumber* uresult, UFieldPosition
|
|||
return;
|
||||
}
|
||||
|
||||
auto* helper = reinterpret_cast<FieldPositionIterator*>(ufpositer);
|
||||
result->string.getAllFieldPositions(*helper, *ec);
|
||||
auto* fpi = reinterpret_cast<FieldPositionIterator*>(ufpositer);
|
||||
FieldPositionIteratorHandler fpih(fpi, *ec);
|
||||
result->string.getAllFieldPositions(fpih, *ec);
|
||||
}
|
||||
|
||||
U_CAPI void U_EXPORT2
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "number_utils.h"
|
||||
#include "number_utypes.h"
|
||||
#include "util.h"
|
||||
#include "fphdlimp.h"
|
||||
|
||||
using namespace icu;
|
||||
using namespace icu::number;
|
||||
|
@ -813,17 +814,16 @@ UBool FormattedNumber::nextFieldPosition(FieldPosition& fieldPosition, UErrorCod
|
|||
}
|
||||
|
||||
void FormattedNumber::populateFieldPositionIterator(FieldPositionIterator& iterator, UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
if (fResults == nullptr) {
|
||||
status = fErrorCode;
|
||||
return;
|
||||
}
|
||||
fResults->string.getAllFieldPositions(iterator, status);
|
||||
getAllFieldPositions(iterator, status);
|
||||
}
|
||||
|
||||
void FormattedNumber::getAllFieldPositions(FieldPositionIterator& iterator, UErrorCode& status) const {
|
||||
FieldPositionIteratorHandler fpih(&iterator, status);
|
||||
getAllFieldPositionsImpl(fpih, status);
|
||||
}
|
||||
|
||||
void FormattedNumber::getAllFieldPositionsImpl(FieldPositionIteratorHandler& fpih,
|
||||
UErrorCode& status) const {
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
|
@ -831,7 +831,7 @@ void FormattedNumber::getAllFieldPositions(FieldPositionIterator& iterator, UErr
|
|||
status = fErrorCode;
|
||||
return;
|
||||
}
|
||||
fResults->string.getAllFieldPositions(iterator, status);
|
||||
fResults->string.getAllFieldPositions(fpih, status);
|
||||
}
|
||||
|
||||
void FormattedNumber::getDecimalQuantity(DecimalQuantity& output, UErrorCode& status) const {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
#include "number_stringbuilder.h"
|
||||
#include "unicode/utf16.h"
|
||||
#include "uvectr32.h"
|
||||
|
||||
using namespace icu;
|
||||
using namespace icu::number;
|
||||
|
@ -461,29 +460,18 @@ bool NumberStringBuilder::nextFieldPosition(FieldPosition& fp, UErrorCode& statu
|
|||
return seenStart;
|
||||
}
|
||||
|
||||
void NumberStringBuilder::getAllFieldPositions(FieldPositionIterator& fpi, UErrorCode& status) const {
|
||||
// TODO: Set an initial capacity on uvec?
|
||||
LocalPointer <UVector32> uvec(new UVector32(status), status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
void NumberStringBuilder::getAllFieldPositions(FieldPositionIteratorHandler& fpih,
|
||||
UErrorCode& status) const {
|
||||
Field current = UNUM_FIELD_COUNT;
|
||||
int32_t currentStart = -1;
|
||||
for (int32_t i = 0; i < fLength; i++) {
|
||||
Field field = fieldAt(i);
|
||||
if (current == UNUM_INTEGER_FIELD && field == UNUM_GROUPING_SEPARATOR_FIELD) {
|
||||
// Special case: GROUPING_SEPARATOR counts as an INTEGER.
|
||||
// Add the field, followed by the start index, followed by the end index to uvec.
|
||||
uvec->addElement(UNUM_GROUPING_SEPARATOR_FIELD, status);
|
||||
uvec->addElement(i, status);
|
||||
uvec->addElement(i + 1, status);
|
||||
fpih.addAttribute(UNUM_GROUPING_SEPARATOR_FIELD, i, i + 1);
|
||||
} else if (current != field) {
|
||||
if (current != UNUM_FIELD_COUNT) {
|
||||
// Add the field, followed by the start index, followed by the end index to uvec.
|
||||
uvec->addElement(current, status);
|
||||
uvec->addElement(currentStart, status);
|
||||
uvec->addElement(i, status);
|
||||
fpih.addAttribute(current, currentStart, i);
|
||||
}
|
||||
current = field;
|
||||
currentStart = i;
|
||||
|
@ -493,14 +481,8 @@ void NumberStringBuilder::getAllFieldPositions(FieldPositionIterator& fpi, UErro
|
|||
}
|
||||
}
|
||||
if (current != UNUM_FIELD_COUNT) {
|
||||
// Add the field, followed by the start index, followed by the end index to uvec.
|
||||
uvec->addElement(current, status);
|
||||
uvec->addElement(currentStart, status);
|
||||
uvec->addElement(fLength, status);
|
||||
fpih.addAttribute(current, currentStart, fLength);
|
||||
}
|
||||
|
||||
// Give uvec to the FieldPositionIterator, which adopts it.
|
||||
fpi.setData(uvec.orphan(), status);
|
||||
}
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "cstring.h"
|
||||
#include "uassert.h"
|
||||
#include "number_types.h"
|
||||
#include "fphdlimp.h"
|
||||
|
||||
U_NAMESPACE_BEGIN namespace number {
|
||||
namespace impl {
|
||||
|
@ -103,7 +104,7 @@ class U_I18N_API NumberStringBuilder : public UMemory {
|
|||
|
||||
bool nextFieldPosition(FieldPosition& fp, UErrorCode& status) const;
|
||||
|
||||
void getAllFieldPositions(FieldPositionIterator& fpi, UErrorCode& status) const;
|
||||
void getAllFieldPositions(FieldPositionIteratorHandler& fpih, UErrorCode& status) const;
|
||||
|
||||
private:
|
||||
bool fUsingHeap = false;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "decContext.h"
|
||||
#include "decNumber.h"
|
||||
#include "double-conversion.h"
|
||||
#include "fphdlimp.h"
|
||||
#include "uresimp.h"
|
||||
#include "ureslocs.h"
|
||||
#include "number_utypes.h"
|
||||
|
@ -111,7 +112,8 @@ UnicodeString& LocalizedNumberFormatterAsFormat::format(const Formattable& obj,
|
|||
}
|
||||
appendTo.append(data.string.toTempUnicodeString());
|
||||
if (posIter != nullptr) {
|
||||
data.string.getAllFieldPositions(*posIter, status);
|
||||
FieldPositionIteratorHandler fpih(posIter, status);
|
||||
data.string.getAllFieldPositions(fpih, status);
|
||||
}
|
||||
return appendTo;
|
||||
}
|
||||
|
|
|
@ -2130,6 +2130,9 @@ class U_I18N_API DecimalFormat : public NumberFormat {
|
|||
static void fieldPositionHelper(const number::FormattedNumber& formatted, FieldPosition& fieldPosition,
|
||||
int32_t offset, UErrorCode& status);
|
||||
|
||||
static void fieldPositionIteratorHelper(const number::FormattedNumber& formatted,
|
||||
FieldPositionIterator* fpi, int32_t offset, UErrorCode& status);
|
||||
|
||||
void setupFastFormat();
|
||||
|
||||
bool fastFormatDouble(double input, UnicodeString& output) const;
|
||||
|
|
|
@ -47,13 +47,6 @@ U_NAMESPACE_BEGIN
|
|||
|
||||
class UVector32;
|
||||
|
||||
// Forward declaration for number formatting:
|
||||
namespace number {
|
||||
namespace impl {
|
||||
class NumberStringBuilder;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* FieldPositionIterator returns the field ids and their start/limit positions generated
|
||||
* by a call to Format::format. See Format, NumberFormat, DecimalFormat.
|
||||
|
@ -114,7 +107,6 @@ private:
|
|||
void setData(UVector32 *adopt, UErrorCode& status);
|
||||
|
||||
friend class FieldPositionIteratorHandler;
|
||||
friend class number::impl::NumberStringBuilder;
|
||||
|
||||
UVector32 *data;
|
||||
int32_t pos;
|
||||
|
|
|
@ -80,6 +80,7 @@ U_NAMESPACE_BEGIN
|
|||
|
||||
// Forward declarations:
|
||||
class IFixedDecimal;
|
||||
class FieldPositionIteratorHandler;
|
||||
|
||||
namespace numparse {
|
||||
namespace impl {
|
||||
|
@ -2515,6 +2516,12 @@ class U_I18N_API FormattedNumber : public UMemory {
|
|||
*/
|
||||
void getDecimalQuantity(impl::DecimalQuantity& output, UErrorCode& status) const;
|
||||
|
||||
/**
|
||||
* Populates the mutable builder type FieldPositionIteratorHandler.
|
||||
* @internal
|
||||
*/
|
||||
void getAllFieldPositionsImpl(FieldPositionIteratorHandler& fpih, UErrorCode& status) const;
|
||||
|
||||
#endif
|
||||
|
||||
// Don't allow copying of FormattedNumber, but moving is okay.
|
||||
|
|
|
@ -212,6 +212,7 @@ void NumberFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &n
|
|||
TESTCASE_AUTO(Test11913_BigDecimal);
|
||||
TESTCASE_AUTO(Test11020_RoundingInScientificNotation);
|
||||
TESTCASE_AUTO(Test11640_TripleCurrencySymbol);
|
||||
TESTCASE_AUTO(Test13763_FieldPositionIteratorOffset);
|
||||
TESTCASE_AUTO_END;
|
||||
}
|
||||
|
||||
|
@ -9048,4 +9049,22 @@ void NumberFormatTest::Test11640_TripleCurrencySymbol() {
|
|||
"US dollars ", result);
|
||||
}
|
||||
|
||||
|
||||
void NumberFormatTest::Test13763_FieldPositionIteratorOffset() {
|
||||
IcuTestErrorCode status(*this, "Test13763_FieldPositionIteratorOffset");
|
||||
FieldPositionIterator fpi;
|
||||
UnicodeString result(u"foo\U0001F4FBbar"); // 8 code units
|
||||
LocalPointer<NumberFormat> nf(NumberFormat::createInstance("en", status));
|
||||
nf->format(5142.3, result, &fpi, status);
|
||||
|
||||
int32_t expected[] = {
|
||||
UNUM_GROUPING_SEPARATOR_FIELD, 9, 10,
|
||||
UNUM_INTEGER_FIELD, 8, 13,
|
||||
UNUM_DECIMAL_SEPARATOR_FIELD, 13, 14,
|
||||
UNUM_FRACTION_FIELD, 14, 15,
|
||||
};
|
||||
int32_t tupleCount = UPRV_LENGTHOF(expected)/3;
|
||||
expectPositions(fpi, expected, tupleCount, result);
|
||||
}
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
|
|
@ -276,6 +276,7 @@ class NumberFormatTest: public CalendarTimeZoneTest {
|
|||
void Test11913_BigDecimal();
|
||||
void Test11020_RoundingInScientificNotation();
|
||||
void Test11640_TripleCurrencySymbol();
|
||||
void Test13763_FieldPositionIteratorOffset();
|
||||
|
||||
private:
|
||||
UBool testFormattableAsUFormattable(const char *file, int line, Formattable &f);
|
||||
|
|
Loading…
Add table
Reference in a new issue