// Used to format durations like 5:47 or 21:35:42. class NumericDateFormatters : public UMemory { public: // Formats like H:mm
UnicodeString hourMinute;
// formats like M:ss
UnicodeString minuteSecond;
// formats like H:mm:ss
UnicodeString hourMinuteSecond;
// Constructor that takes the actual patterns for hour-minute, // minute-second, and hour-minute-second respectively.
NumericDateFormatters( const UnicodeString &hm, const UnicodeString &ms, const UnicodeString &hms) :
hourMinute(hm),
minuteSecond(ms),
hourMinuteSecond(hms) {
} private:
NumericDateFormatters(const NumericDateFormatters &other);
NumericDateFormatters &operator=(const NumericDateFormatters &other);
};
static UNumberUnitWidth getUnitWidth(UMeasureFormatWidth width) { switch (width) { case UMEASFMT_WIDTH_WIDE: return UNUM_UNIT_WIDTH_FULL_NAME; case UMEASFMT_WIDTH_NARROW: case UMEASFMT_WIDTH_NUMERIC: return UNUM_UNIT_WIDTH_NARROW; case UMEASFMT_WIDTH_SHORT: default: return UNUM_UNIT_WIDTH_SHORT;
}
}
/** * Instances contain all MeasureFormat specific data for a particular locale. * This data is cached. It is never copied, but is shared via shared pointers. * * Note: We might change the cache data to have an array[WIDTH_INDEX_COUNT] of * complete sets of unit & per patterns, * to correspond to the resource data and its aliases. * * TODO: Maybe store more sparsely in general, with pointers rather than potentially-empty objects.
*/ class MeasureFormatCacheData : public SharedObject { public:
/** * Redirection data from root-bundle, top-level sideways aliases. * - UMEASFMT_WIDTH_COUNT: initial value, just fall back to root * - UMEASFMT_WIDTH_WIDE/SHORT/NARROW: sideways alias for missing data
*/
UMeasureFormatWidth widthFallback[WIDTH_INDEX_COUNT];
MeasureFormatCacheData::MeasureFormatCacheData()
: integerFormat(nullptr), numericDateFormatters(nullptr) { for (int32_t i = 0; i < WIDTH_INDEX_COUNT; ++i) {
widthFallback[i] = UMEASFMT_WIDTH_COUNT;
}
memset(currencyFormats, 0, sizeof(currencyFormats));
}
MeasureFormatCacheData::~MeasureFormatCacheData() { for (int32_t i = 0; i < UPRV_LENGTHOF(currencyFormats); ++i) { delete currencyFormats[i];
} // Note: the contents of 'dnams' are pointers into the resource bundle delete integerFormat; delete numericDateFormatters;
}
// Converts a composite measure into hours-minutes-seconds and stores at hms // array. [0] is hours; [1] is minutes; [2] is seconds. Returns a bit map of // units found: 1=hours, 2=minutes, 4=seconds. For example, if measures // contains hours-minutes, this function would return 3. // // If measures cannot be converted into hours, minutes, seconds or if amounts // are negative, or if hours, minutes, seconds are out of order, returns 0. static int32_t toHMS( const Measure *measures,
int32_t measureCount,
Formattable *hms,
UErrorCode &status) { if (U_FAILURE(status)) { return 0;
}
int32_t result = 0; if (U_FAILURE(status)) { return 0;
} // We use copy constructor to ensure that both sides of equality operator // are instances of MeasureUnit base class and not a subclass. Otherwise, // operator== will immediately return false. for (int32_t i = 0; i < measureCount; ++i) { if (isTimeUnit(measures[i].getUnit(), "hour")) { // hour must come first if (result >= 1) { return 0;
}
hms[0] = measures[i].getNumber(); if (hms[0].getDouble() < 0.0) { return 0;
}
result |= 1;
} elseif (isTimeUnit(measures[i].getUnit(), "minute")) { // minute must come after hour if (result >= 2) { return 0;
}
hms[1] = measures[i].getNumber(); if (hms[1].getDouble() < 0.0) { return 0;
}
result |= 2;
} elseif (isTimeUnit(measures[i].getUnit(), "second")) { // second must come after hour and minute if (result >= 4) { return 0;
}
hms[2] = measures[i].getNumber(); if (hms[2].getDouble() < 0.0) { return 0;
}
result |= 4;
} else { return 0;
}
} return result;
}
MeasureFormat::~MeasureFormat() { if (cache != nullptr) {
cache->removeRef();
} if (numberFormat != nullptr) {
numberFormat->removeRef();
} if (pluralRules != nullptr) {
pluralRules->removeRef();
} delete listFormatter;
}
bool MeasureFormat::operator==(const Format &other) const { if (this == &other) { // Same object, equal returntrue;
} if (!Format::operator==(other)) { returnfalse;
} const MeasureFormat &rhs = static_cast<const MeasureFormat &>(other);
// Note: Since the ListFormatter depends only on Locale and width, we // don't have to check it here.
// differing widths aren't equivalent if (fWidth != rhs.fWidth) { returnfalse;
} // Width the same check locales. // We don't need to check locales if both objects have same cache. if (cache != rhs.cache) {
UErrorCode status = U_ZERO_ERROR; constchar *localeId = getLocaleID(status); constchar *rhsLocaleId = rhs.getLocaleID(status); if (U_FAILURE(status)) { // On failure, assume not equal returnfalse;
} if (uprv_strcmp(localeId, rhsLocaleId) != 0) { returnfalse;
}
} // Locales same, check NumberFormat if shared data differs. return (
numberFormat == rhs.numberFormat ||
**numberFormat == **rhs.numberFormat);
}
UBool protect = false; const int32_t patternLength = pattern.length(); for (int32_t i = 0; i < patternLength; i++) {
char16_t c = pattern[i];
// Also set the proper field in this switch // We don't use DateFormat.Field because this is not a date / time, is a duration. double value = 0; switch (c) { case u'H': value = hours; break; case u'm': value = minutes; break; case u's': value = seconds; break;
}
// There is not enough info to add Field(s) for the unit because all we have are plain // text patterns. For example in "21:51" there is no text for something like "hour", // while in something like "21h51" there is ("h"). But we can't really tell... switch (c) { case u'H': case u'm': case u's': if (protect) {
fsb.appendChar16(c, kUndefinedField, status);
} else {
UnicodeString tmp; if ((i + 1 < patternLength) && pattern[i + 1] == c) { // doubled
tmp = numberFormatter2.formatDouble(value, status).toString(status);
i++;
} else {
numberFormatter->format(value, tmp, status);
} // TODO: Use proper Field
fsb.append(tmp, kUndefinedField, status);
} break; case u'\'': // '' is escaped apostrophe if ((i + 1 < patternLength) && pattern[i + 1] == c) {
fsb.appendChar16(c, kUndefinedField, status);
i++;
} else {
protect = !protect;
} break; default:
fsb.appendChar16(c, kUndefinedField, status);
}
}
appendTo.append(fsb.toTempUnicodeString());
return appendTo;
}
UnicodeString &MeasureFormat::formatMeasuresSlowTrack( const Measure *measures,
int32_t measureCount,
UnicodeString& appendTo,
FieldPosition& pos,
UErrorCode& status) const { if (U_FAILURE(status)) { return appendTo;
}
FieldPosition dontCare(FieldPosition::DONT_CARE);
FieldPosition fpos(pos.getField());
LocalArray<UnicodeString> results(new UnicodeString[measureCount], status);
int32_t fieldPositionFoundIndex = -1; for (int32_t i = 0; i < measureCount; ++i) { const NumberFormat *nf = cache->getIntegerFormat(); if (i == measureCount - 1) {
nf = numberFormat->get();
} if (fieldPositionFoundIndex == -1) {
formatMeasure(measures[i], *nf, results[i], fpos, status); if (U_FAILURE(status)) { return appendTo;
} if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) {
fieldPositionFoundIndex = i;
}
} else {
formatMeasure(measures[i], *nf, results[i], dontCare, status);
}
}
int32_t offset;
listFormatter->format(
results.getAlias(),
measureCount,
appendTo,
fieldPositionFoundIndex,
offset,
status); if (U_FAILURE(status)) { return appendTo;
} // Fix up FieldPosition indexes if our field is found. if (fieldPositionFoundIndex != -1 && offset != -1) {
pos.setBeginIndex(fpos.getBeginIndex() + offset);
pos.setEndIndex(fpos.getEndIndex() + offset);
} return appendTo;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.