TimeUnitFormat&
TimeUnitFormat::operator=(const TimeUnitFormat& other) { if (this == &other) { return *this;
}
MeasureFormat::operator=(other); for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
i = static_cast<TimeUnit::UTimeUnitFields>(i + 1)) {
deleteHash(fTimeUnitToCountToPatterns[i]);
fTimeUnitToCountToPatterns[i] = nullptr;
} for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
i = static_cast<TimeUnit::UTimeUnitFields>(i + 1)) {
UErrorCode status = U_ZERO_ERROR;
fTimeUnitToCountToPatterns[i] = initHash(status); if (U_SUCCESS(status)) {
copyHash(other.fTimeUnitToCountToPatterns[i], fTimeUnitToCountToPatterns[i], status);
} else { delete fTimeUnitToCountToPatterns[i];
fTimeUnitToCountToPatterns[i] = nullptr;
}
}
fStyle = other.fStyle; return *this;
}
void
TimeUnitFormat::parseObject(const UnicodeString& source,
Formattable& result,
ParsePosition& pos) const {
Formattable resultNumber(0.0);
UBool withNumberFormat = false;
TimeUnit::UTimeUnitFields resultTimeUnit = TimeUnit::UTIMEUNIT_FIELD_COUNT;
int32_t oldPos = pos.getIndex();
int32_t newPos = -1;
int32_t longestParseDistance = 0;
UnicodeString* countOfLongestMatch = nullptr; #ifdef TMUTFMT_DEBUG char res[1000];
source.extract(0, source.length(), res, "UTF-8");
std::cout << "parse source: " << res << "\n"; #endif // parse by iterating through all available patterns // and looking for the longest match. for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
i = static_cast<TimeUnit::UTimeUnitFields>(i + 1)) {
Hashtable* countToPatterns = fTimeUnitToCountToPatterns[i];
int32_t elemPos = UHASH_FIRST; const UHashElement* elem = nullptr; while ((elem = countToPatterns->nextElement(elemPos)) != nullptr){ const UHashTok keyTok = elem->key;
UnicodeString* count = static_cast<UnicodeString*>(keyTok.pointer); #ifdef TMUTFMT_DEBUG
count->extract(0, count->length(), res, "UTF-8");
std::cout << "parse plural count: " << res << "\n"; #endif const UHashTok valueTok = elem->value; // the value is a pair of MessageFormat*
MessageFormat** patterns = static_cast<MessageFormat**>(valueTok.pointer); for (UTimeUnitFormatStyle style = UTMUTFMT_FULL_STYLE; style < UTMUTFMT_FORMAT_STYLE_COUNT;
style = static_cast<UTimeUnitFormatStyle>(style + 1)) {
MessageFormat* pattern = patterns[style];
pos.setErrorIndex(-1);
pos.setIndex(oldPos); // see if we can parse
Formattable parsed;
pattern->parseObject(source, parsed, pos); if (pos.getErrorIndex() != -1 || pos.getIndex() == oldPos) { continue;
} #ifdef TMUTFMT_DEBUG
std::cout << "parsed.getType: " << parsed.getType() << "\n"; #endif
Formattable tmpNumber(0.0); if (pattern->getArgTypeCount() != 0) {
Formattable& temp = parsed[0]; if (temp.getType() == Formattable::kString) {
UnicodeString tmpString;
UErrorCode pStatus = U_ZERO_ERROR;
getNumberFormatInternal().parse(temp.getString(tmpString), tmpNumber, pStatus); if (U_FAILURE(pStatus)) { continue;
}
} elseif (temp.isNumeric()) {
tmpNumber = temp;
} else { continue;
}
}
int32_t parseDistance = pos.getIndex() - oldPos; if (parseDistance > longestParseDistance) { if (pattern->getArgTypeCount() != 0) {
resultNumber = tmpNumber;
withNumberFormat = true;
} else {
withNumberFormat = false;
}
resultTimeUnit = i;
newPos = pos.getIndex();
longestParseDistance = parseDistance;
countOfLongestMatch = count;
}
}
}
} /* After find the longest match, parse the number. * Result number could be null for the pattern without number pattern. * such as unit pattern in Arabic. * When result number is null, use plural rule to set the number.
*/ if (withNumberFormat == false && longestParseDistance != 0) { // set the number using plurrual count if (0 == countOfLongestMatch->compare(PLURAL_COUNT_ZERO, 4)) {
resultNumber = Formattable(0.0);
} elseif (0 == countOfLongestMatch->compare(PLURAL_COUNT_ONE, 3)) {
resultNumber = Formattable(1.0);
} elseif (0 == countOfLongestMatch->compare(PLURAL_COUNT_TWO, 3)) {
resultNumber = Formattable(2.0);
} else { // should not happen. // TODO: how to handle?
resultNumber = Formattable(3.0);
}
} if (longestParseDistance == 0) {
pos.setIndex(oldPos);
pos.setErrorIndex(0);
} else {
UErrorCode status = U_ZERO_ERROR;
LocalPointer<TimeUnitAmount> tmutamt(new TimeUnitAmount(resultNumber, resultTimeUnit, status), status); if (U_SUCCESS(status)) {
result.adoptObject(tmutamt.orphan());
pos.setIndex(newPos);
pos.setErrorIndex(-1);
} else {
pos.setIndex(oldPos);
pos.setErrorIndex(0);
}
}
}
void
TimeUnitFormat::create(UTimeUnitFormatStyle style, UErrorCode& status) { // fTimeUnitToCountToPatterns[] must have its elements initialized to nullptr first // before checking for failure status. for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
i = static_cast<TimeUnit::UTimeUnitFields>(i + 1)) {
fTimeUnitToCountToPatterns[i] = nullptr;
}
if (U_FAILURE(status)) { return;
} if (style < UTMUTFMT_FULL_STYLE || style >= UTMUTFMT_FORMAT_STYLE_COUNT) {
status = U_ILLEGAL_ARGUMENT_ERROR; return;
}
fStyle = style;
//TODO: format() and parseObj() are const member functions, //so, can not do lazy initialization in C++. //setup has to be done in constructors. //and here, the behavior is not consistent with Java. //In Java, create an empty instance does not setup locale as //default locale. If it followed by setNumberFormat(), //in format(), the locale will set up as the locale in fNumberFormat. //But in C++, this sets the locale as the default locale.
setup(status);
}
void
TimeUnitFormat::readFromCurrentLocale(UTimeUnitFormatStyle style, constchar* key, const UVector& pluralCounts, UErrorCode& err) { if (U_FAILURE(err)) { return;
} // fill timeUnitToCountToPatterns from resource file // err is used to indicate wrong status except missing resource. // status is an error code used in resource lookup. // status does not affect "err".
UErrorCode status = U_ZERO_ERROR;
LocalUResourceBundlePointer rb(ures_open(U_ICUDATA_UNIT, getLocaleID(status), &status));
void
TimeUnitFormat::checkConsistency(UTimeUnitFormatStyle style, constchar* key, UErrorCode& err) { if (U_FAILURE(err)) { return;
} // there should be patterns for each plural rule in each time unit. // For each time unit, // for each plural rule, following is unit pattern fall-back rule: // ( for example: "one" hour ) // look for its unit pattern in its locale tree. // if pattern is not found in its own locale, such as de_DE, // look for the pattern in its parent, such as de, // keep looking till found or till root. // if the pattern is not found in root either, // fallback to plural count "other", // look for the pattern of "other" in the locale tree: // "de_DE" to "de" to "root". // If not found, fall back to value of // static variable DEFAULT_PATTERN_FOR_xxx, such as "{0} h". // // Following is consistency check to create pattern for each // plural rule in each time unit using above fall-back rule. //
LocalPointer<StringEnumeration> keywords(
getPluralRules().getKeywords(err), err); const UnicodeString* pluralCount; while (U_SUCCESS(err) && (pluralCount = keywords->snext(err)) != nullptr) { for (int32_t i = 0; i < TimeUnit::UTIMEUNIT_FIELD_COUNT; ++i) { // for each time unit, // get all the patterns for each plural rule in this locale.
Hashtable* countToPatterns = fTimeUnitToCountToPatterns[i]; if ( countToPatterns == nullptr ) {
fTimeUnitToCountToPatterns[i] = countToPatterns = initHash(err); if (U_FAILURE(err)) { return;
}
}
MessageFormat** formatters = static_cast<MessageFormat**>(countToPatterns->get(*pluralCount)); if( formatters == nullptr || formatters[style] == nullptr ) { // look through parents constchar* localeName = getLocaleID(err);
CharString pluralCountChars;
pluralCountChars.appendInvariantChars(*pluralCount, err);
searchInLocaleChain(style, key, localeName, static_cast<TimeUnit::UTimeUnitFields>(i),
*pluralCount, pluralCountChars.data(),
countToPatterns, err);
} // TODO: what to do with U_FAILURE(err) at this point. // As is, the outer loop continues to run, but does nothing.
}
}
}
// srcPluralCount is the original plural count on which the pattern is // searched for. // searchPluralCount is the fallback plural count. // For example, to search for pattern for ""one" hour", // "one" is the srcPluralCount, // if the pattern is not found even in root, fallback to // using patterns of plural count "other", // then, "other" is the searchPluralCount. void
TimeUnitFormat::searchInLocaleChain(UTimeUnitFormatStyle style, constchar* key, constchar* localeName,
TimeUnit::UTimeUnitFields srcTimeUnitField, const UnicodeString& srcPluralCount, constchar* searchPluralCount,
Hashtable* countToPatterns,
UErrorCode& err) { if (U_FAILURE(err)) { return;
}
UErrorCode status = U_ZERO_ERROR;
CharString parentLocale(localeName, status);
U_ASSERT(countToPatterns != nullptr); for (;;) {
parentLocale = ulocimp_getParent(parentLocale.data(), status); // look for pattern for srcPluralCount in locale tree
LocalUResourceBundlePointer rb(ures_open(U_ICUDATA_UNIT, parentLocale.data(), &status));
LocalUResourceBundlePointer unitsRes(ures_getByKey(rb.getAlias(), key, nullptr, &status)); constchar* timeUnitName = getTimeUnitName(srcTimeUnitField, status);
LocalUResourceBundlePointer countsToPatternRB(ures_getByKey(unitsRes.getAlias(), timeUnitName, nullptr, &status)); const char16_t* pattern;
int32_t ptLength;
pattern = ures_getStringByKeyWithFallback(countsToPatternRB.getAlias(), searchPluralCount, &ptLength, &status); if (U_SUCCESS(status)) { //found
LocalPointer<MessageFormat> messageFormat( new MessageFormat(UnicodeString(true, pattern, ptLength), getLocale(err), err), err); if (U_FAILURE(err)) { return;
}
MessageFormat** formatters = static_cast<MessageFormat**>(countToPatterns->get(srcPluralCount)); if (formatters == nullptr) {
LocalMemory<MessageFormat *> localFormatters( static_cast<MessageFormat**>(uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT * sizeof(MessageFormat*))));
formatters = localFormatters.getAlias();
localFormatters[UTMUTFMT_FULL_STYLE] = nullptr;
localFormatters[UTMUTFMT_ABBREVIATED_STYLE] = nullptr;
countToPatterns->put(srcPluralCount, localFormatters.orphan(), err); if (U_FAILURE(err)) { return;
}
} //delete formatters[style];
formatters[style] = messageFormat.orphan(); return;
}
status = U_ZERO_ERROR; if (parentLocale.isEmpty()) { break;
}
}
// if no unitsShort resource was found even after fallback to root locale // then search the units resource fallback from the current level to root if ( parentLocale.isEmpty() && uprv_strcmp(key, gShortUnitsTag) == 0) { #ifdef TMUTFMT_DEBUG
std::cout << "loop into searchInLocaleChain since Short-Long-Alternative \n"; #endif
CharString pLocale(localeName, -1, err); // Add an underscore at the tail of locale name, // so that searchInLocaleChain will check the current locale before falling back
pLocale.append('_', err);
searchInLocaleChain(style, gUnitsTag, pLocale.data(), srcTimeUnitField, srcPluralCount,
searchPluralCount, countToPatterns, err); if (U_FAILURE(err)) { return;
}
MessageFormat** formatters = static_cast<MessageFormat**>(countToPatterns->get(srcPluralCount)); if (formatters != nullptr && formatters[style] != nullptr) { return;
}
}
// if not found the pattern for this plural count at all, // fall-back to plural count "other" if ( uprv_strcmp(searchPluralCount, gPluralCountOther) == 0 ) { // set default fall back the same as the resource in root
LocalPointer<MessageFormat> messageFormat; const char16_t *pattern = nullptr; if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_SECOND ) {
pattern = DEFAULT_PATTERN_FOR_SECOND;
} elseif ( srcTimeUnitField == TimeUnit::UTIMEUNIT_MINUTE ) {
pattern = DEFAULT_PATTERN_FOR_MINUTE;
} elseif ( srcTimeUnitField == TimeUnit::UTIMEUNIT_HOUR ) {
pattern = DEFAULT_PATTERN_FOR_HOUR;
} elseif ( srcTimeUnitField == TimeUnit::UTIMEUNIT_WEEK ) {
pattern = DEFAULT_PATTERN_FOR_WEEK;
} elseif ( srcTimeUnitField == TimeUnit::UTIMEUNIT_DAY ) {
pattern = DEFAULT_PATTERN_FOR_DAY;
} elseif ( srcTimeUnitField == TimeUnit::UTIMEUNIT_MONTH ) {
pattern = DEFAULT_PATTERN_FOR_MONTH;
} elseif ( srcTimeUnitField == TimeUnit::UTIMEUNIT_YEAR ) {
pattern = DEFAULT_PATTERN_FOR_YEAR;
} if (pattern != nullptr) {
messageFormat.adoptInsteadAndCheckErrorCode( new MessageFormat(UnicodeString(true, pattern, -1), getLocale(err), err), err);
} if (U_FAILURE(err)) { return;
}
MessageFormat** formatters = static_cast<MessageFormat**>(countToPatterns->get(srcPluralCount)); if (formatters == nullptr) {
LocalMemory<MessageFormat *> localFormatters ( static_cast<MessageFormat**>(uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT * sizeof(MessageFormat*)))); if (localFormatters.isNull()) {
err = U_MEMORY_ALLOCATION_ERROR; return;
}
formatters = localFormatters.getAlias();
formatters[UTMUTFMT_FULL_STYLE] = nullptr;
formatters[UTMUTFMT_ABBREVIATED_STYLE] = nullptr;
countToPatterns->put(srcPluralCount, localFormatters.orphan(), err);
} if (U_SUCCESS(err)) { //delete formatters[style];
formatters[style] = messageFormat.orphan();
}
} else { // fall back to rule "other", and search in parents
searchInLocaleChain(style, key, localeName, srcTimeUnitField, srcPluralCount,
gPluralCountOther, countToPatterns, err);
}
}
/** * set hash table value comparator * * @param val1 one value in comparison * @param val2 the other value in comparison * @return true if 2 values are the same, false otherwise
*/ static UBool U_CALLCONV tmutfmtHashTableValueComparator(UHashTok val1, UHashTok val2);
Hashtable*
TimeUnitFormat::initHash(UErrorCode& status) { if ( U_FAILURE(status) ) { return nullptr;
}
Hashtable* hTable; if ( (hTable = new Hashtable(true, status)) == nullptr ) {
status = U_MEMORY_ALLOCATION_ERROR; return nullptr;
} if ( U_FAILURE(status) ) { delete hTable; return nullptr;
}
hTable->setValueComparator(tmutfmtHashTableValueComparator); return hTable;
}
constchar*
TimeUnitFormat::getTimeUnitName(TimeUnit::UTimeUnitFields unitField,
UErrorCode& status) { if (U_FAILURE(status)) { return nullptr;
} switch (unitField) { case TimeUnit::UTIMEUNIT_YEAR: return gTimeUnitYear; case TimeUnit::UTIMEUNIT_MONTH: return gTimeUnitMonth; case TimeUnit::UTIMEUNIT_DAY: return gTimeUnitDay; case TimeUnit::UTIMEUNIT_WEEK: return gTimeUnitWeek; case TimeUnit::UTIMEUNIT_HOUR: return gTimeUnitHour; case TimeUnit::UTIMEUNIT_MINUTE: return gTimeUnitMinute; case TimeUnit::UTIMEUNIT_SECOND: return gTimeUnitSecond; default:
status = U_ILLEGAL_ARGUMENT_ERROR; return nullptr;
}
}
U_NAMESPACE_END
#endif
Messung V0.5
¤ 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.0.17Bemerkung:
(vorverarbeitet)
¤
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.