// Get the appropriate sub-message. // Select it based on the formatted number-offset. double numberMinusOffset = number - offset; // Call NumberFormatter to get both the DecimalQuantity and the string. // This call site needs to use more internal APIs than the Java equivalent.
number::impl::UFormattedNumberData data; if (offset == 0) { // could be BigDecimal etc.
numberObject.populateDecimalQuantity(data.quantity, status);
} else {
data.quantity.setToDouble(numberMinusOffset);
}
UnicodeString numberString; auto *decFmt = dynamic_cast<DecimalFormat *>(numberFormat); if(decFmt != nullptr) { const number::LocalizedNumberFormatter* lnf = decFmt->toNumberFormatter(status); if (U_FAILURE(status)) { return appendTo;
}
lnf->formatImpl(&data, status); // mutates &data if (U_FAILURE(status)) { return appendTo;
}
numberString = data.getStringRef().toUnicodeString();
} else { if (offset == 0) {
numberFormat->format(numberObject, numberString, status);
} else {
numberFormat->format(numberMinusOffset, numberString, status);
}
}
int32_t partIndex = findSubMessage(msgPattern, 0, pluralRulesWrapper, &data.quantity, number, status); if (U_FAILURE(status)) { return appendTo; } // Replace syntactic # signs in the top level of this sub-message // (not in nested arguments) with the formatted number-offset. const UnicodeString& pattern = msgPattern.getPatternString();
int32_t prevIndex = msgPattern.getPart(partIndex).getLimit(); for (;;) { const MessagePattern::Part& part = msgPattern.getPart(++partIndex); const UMessagePatternPartType type = part.getType();
int32_t index = part.getIndex(); if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) { return appendTo.append(pattern, prevIndex, index - prevIndex);
} elseif ((type == UMSGPAT_PART_TYPE_REPLACE_NUMBER) ||
(type == UMSGPAT_PART_TYPE_SKIP_SYNTAX && MessageImpl::jdkAposMode(msgPattern))) {
appendTo.append(pattern, prevIndex, index - prevIndex); if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER) {
appendTo.append(numberString);
}
prevIndex = part.getLimit();
} elseif (type == UMSGPAT_PART_TYPE_ARG_START) {
appendTo.append(pattern, prevIndex, index - prevIndex);
prevIndex = index;
partIndex = msgPattern.getLimitPartIndex(partIndex);
index = msgPattern.getPart(partIndex).getLimit();
MessageImpl::appendReducedApostrophes(pattern, prevIndex, index, appendTo);
prevIndex = index;
}
}
}
int32_t PluralFormat::findSubMessage(const MessagePattern& pattern, int32_t partIndex, const PluralSelector& selector, void *context, double number, UErrorCode& ec) { if (U_FAILURE(ec)) { return 0;
}
int32_t count=pattern.countParts(); double offset; const MessagePattern::Part* part=&pattern.getPart(partIndex); if (MessagePattern::Part::hasNumericValue(part->getType())) {
offset=pattern.getNumericValue(*part);
++partIndex;
} else {
offset=0;
} // The keyword is empty until we need to match against a non-explicit, not-"other" value. // Then we get the keyword from the selector. // (In other words, we never call the selector if we match against an explicit value, // or if the only non-explicit keyword is "other".)
UnicodeString keyword;
UnicodeString other(false, OTHER_STRING, 5); // When we find a match, we set msgStart>0 and also set this boolean to true // to avoid matching the keyword again (duplicates are allowed) // while we continue to look for an explicit-value match.
UBool haveKeywordMatch=false; // msgStart is 0 until we find any appropriate sub-message. // We remember the first "other" sub-message if we have not seen any // appropriate sub-message before. // We remember the first matching-keyword sub-message if we have not seen // one of those before. // (The parser allows [does not check for] duplicate keywords. // We just have to make sure to take the first one.) // We avoid matching the keyword twice by also setting haveKeywordMatch=true // at the first keyword match. // We keep going until we find an explicit-value match or reach the end of the plural style.
int32_t msgStart=0; // Iterate over (ARG_SELECTOR [ARG_INT|ARG_DOUBLE] message) tuples // until ARG_LIMIT or end of plural-only pattern. do {
part=&pattern.getPart(partIndex++); const UMessagePatternPartType type = part->getType(); if(type==UMSGPAT_PART_TYPE_ARG_LIMIT) { break;
}
U_ASSERT (type==UMSGPAT_PART_TYPE_ARG_SELECTOR); // part is an ARG_SELECTOR followed by an optional explicit value, and then a message if(MessagePattern::Part::hasNumericValue(pattern.getPartType(partIndex))) { // explicit value like "=2"
part=&pattern.getPart(partIndex++); if(number==pattern.getNumericValue(*part)) { // matches explicit value return partIndex;
}
} elseif(!haveKeywordMatch) { // plural keyword like "few" or "other" // Compare "other" first and call the selector if this is not "other". if(pattern.partSubstringMatches(*part, other)) { if(msgStart==0) {
msgStart=partIndex; if(0 == keyword.compare(other)) { // This is the first "other" sub-message, // and the selected keyword is also "other". // Do not match "other" again.
haveKeywordMatch=true;
}
}
} else { if(keyword.isEmpty()) {
keyword=selector.select(context, number-offset, ec); if(msgStart!=0 && (0 == keyword.compare(other))) { // We have already seen an "other" sub-message. // Do not match "other" again.
haveKeywordMatch=true; // Skip keyword matching but do getLimitPartIndex().
}
} if(!haveKeywordMatch && pattern.partSubstringMatches(*part, keyword)) { // keyword matches
msgStart=partIndex; // Do not match this keyword again.
haveKeywordMatch=true;
}
}
}
partIndex=pattern.getLimitPartIndex(partIndex);
} while(++partIndex<count); return msgStart;
}
void PluralFormat::parseType(const UnicodeString& source, const NFRule *rbnfLenientScanner, Formattable& result, FieldPosition& pos) const { // If no pattern was applied, return null. if (msgPattern.countParts() == 0) {
pos.setBeginIndex(-1);
pos.setEndIndex(-1); return;
} int partIndex = 0; int currMatchIndex; int count=msgPattern.countParts(); int startingAt = pos.getBeginIndex(); if (startingAt < 0) {
startingAt = 0;
}
// The keyword is null until we need to match against a non-explicit, not-"other" value. // Then we get the keyword from the selector. // (In other words, we never call the selector if we match against an explicit value, // or if the only non-explicit keyword is "other".)
UnicodeString keyword;
UnicodeString matchedWord; const UnicodeString& pattern = msgPattern.getPatternString(); int matchedIndex = -1; // Iterate over (ARG_SELECTOR ARG_START message ARG_LIMIT) tuples // until the end of the plural-only pattern. while (partIndex < count) { const MessagePattern::Part* partSelector = &msgPattern.getPart(partIndex++); if (partSelector->getType() != UMSGPAT_PART_TYPE_ARG_SELECTOR) { // Bad format continue;
}
const MessagePattern::Part* partStart = &msgPattern.getPart(partIndex++); if (partStart->getType() != UMSGPAT_PART_TYPE_MSG_START) { // Bad format continue;
}
const MessagePattern::Part* partLimit = &msgPattern.getPart(partIndex++); if (partLimit->getType() != UMSGPAT_PART_TYPE_MSG_LIMIT) { // Bad format continue;
}
UnicodeString currArg = pattern.tempSubString(partStart->getLimit(), partLimit->getIndex() - partStart->getLimit()); if (rbnfLenientScanner != nullptr) { // Check if non-lenient rule finds the text before call lenient parsing
int32_t tempIndex = source.indexOf(currArg, startingAt); if (tempIndex >= 0) {
currMatchIndex = tempIndex;
} else { // If lenient parsing is turned ON, we've got some time consuming parsing ahead of us.
int32_t length = -1;
currMatchIndex = rbnfLenientScanner->findTextLenient(source, currArg, startingAt, &length);
}
} else {
currMatchIndex = source.indexOf(currArg, startingAt);
} if (currMatchIndex >= 0 && currMatchIndex >= matchedIndex && currArg.length() > matchedWord.length()) {
matchedIndex = currMatchIndex;
matchedWord = currArg;
keyword = pattern.tempSubString(partStart->getLimit(), partLimit->getIndex() - partStart->getLimit());
}
} if (matchedIndex >= 0) {
pos.setBeginIndex(matchedIndex);
pos.setEndIndex(matchedIndex + matchedWord.length());
result.setString(keyword); return;
}
// Not found!
pos.setBeginIndex(-1);
pos.setEndIndex(-1);
}
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.