UBool Normalizer::previousNormalize() { clearBuffer(); nextIndex = currentIndex; text->setIndex(currentIndex); if (!text->hasPrevious()) { return FALSE; } UnicodeString segment; while (text->hasPrevious()) { UChar32 c = text->previous32(); segment.insert(0, c); if (fNorm2->hasBoundaryBefore(c)) { break; } } currentIndex = text->getIndex(); UErrorCode errorCode = U_ZERO_ERROR; fNorm2->normalize(segment, buffer, errorCode); bufferPos = buffer.length(); return U_SUCCESS(errorCode) && !buffer.isEmpty(); }
/** * Do a normalization using the iterative API in the given direction. * @param dir either +1 or -1 */ void NormalizerConformanceTest::iterativeNorm(const UnicodeString& str, UNormalizationMode mode, int32_t options, UnicodeString& result, int8_t dir) { UErrorCode status = U_ZERO_ERROR; normalizer.setText(str, status); normalizer.setMode(mode); normalizer.setOption(-1, 0); // reset all options normalizer.setOption(options, 1); // set desired options result.truncate(0); if (U_FAILURE(status)) { return; } UChar32 ch; if (dir > 0) { for (ch = normalizer.first(); ch != Normalizer::DONE; ch = normalizer.next()) { result.append(ch); } } else { for (ch = normalizer.last(); ch != Normalizer::DONE; ch = normalizer.previous()) { result.insert(0, ch); } } }
void G7CollationTest::TestDemo3(/* char* par */) { logln("Demo Test 3 : Create a new table collation with rules \"& Question'-'mark ; '?' & Hash'-'mark ; '#' & Ampersand ; '&'\""); UErrorCode status = U_ZERO_ERROR; Collator *col = Collator::createInstance("en_US", status); if(U_FAILURE(status)) { errln("Couldn't instantiate collator. Error: %s", u_errorName(status)); delete col; return; } const UnicodeString baseRules = ((RuleBasedCollator*)col)->getRules(); UnicodeString newRules = "& Question'-'mark ; '?' & Hash'-'mark ; '#' & Ampersand ; '&'"; newRules.insert(0, baseRules); RuleBasedCollator *myCollation = new RuleBasedCollator(newRules, status); if (U_FAILURE(status)) { errln("Demo Test 3 Table Collation object creation failed."); return; } int32_t j, n; for (j = 0; j < TOTALTESTSET; j++) { for (n = j+1; n < TOTALTESTSET; n++) { doTest(myCollation, testCases[results[10][j]], testCases[results[10][n]], Collator::LESS); } } delete myCollation; delete col; }
void G7CollationTest::TestDemo4(/* char* par */) { logln("Demo Test 4 : Create a new table collation with rules \" & aa ; a'-' & ee ; e'-' & ii ; i'-' & oo ; o'-' & uu ; u'-' \""); UErrorCode status = U_ZERO_ERROR; Collator *col = Collator::createInstance("en_US", status); if(U_FAILURE(status)) { delete col; errln("Couldn't instantiate collator. Error: %s", u_errorName(status)); return; } const UnicodeString baseRules = ((RuleBasedCollator*)col)->getRules(); UnicodeString newRules = " & aa ; a'-' & ee ; e'-' & ii ; i'-' & oo ; o'-' & uu ; u'-' "; newRules.insert(0, baseRules); RuleBasedCollator *myCollation = new RuleBasedCollator(newRules, status); int32_t j, n; for (j = 0; j < TOTALTESTSET; j++) { for (n = j+1; n < TOTALTESTSET; n++) { doTest(myCollation, testCases[results[11][j]], testCases[results[11][n]], Collator::LESS); } } delete myCollation; delete col; }
/** * Givens a Spec object, convert it to a SingleID object. The * Spec object is a more unprocessed parse result. The SingleID * object contains information about canonical and basic IDs. * @return a SingleID; never returns NULL. Returned object always * has 'filter' field of NULL. */ TransliteratorIDParser::SingleID* TransliteratorIDParser::specsToID(const Specs* specs, int32_t dir) { UnicodeString canonID; UnicodeString basicID; UnicodeString basicPrefix; if (specs != NULL) { UnicodeString buf; if (dir == FORWARD) { if (specs->sawSource) { buf.append(specs->source).append(TARGET_SEP); } else { basicPrefix = specs->source; basicPrefix.append(TARGET_SEP); } buf.append(specs->target); } else { buf.append(specs->target).append(TARGET_SEP).append(specs->source); } if (specs->variant.length() != 0) { buf.append(VARIANT_SEP).append(specs->variant); } basicID = basicPrefix; basicID.append(buf); if (specs->filter.length() != 0) { buf.insert(0, specs->filter); } canonID = buf; } return new SingleID(canonID, basicID); }
static int32_t _iterate(UCharIterator *src, UBool forward, UChar *dest, int32_t destCapacity, const Normalizer2 *n2, UBool doNormalize, UBool *pNeededToNormalize, UErrorCode *pErrorCode) { if(U_FAILURE(*pErrorCode)) { return 0; } if(destCapacity<0 || (dest==NULL && destCapacity>0) || src==NULL) { *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; return 0; } if(pNeededToNormalize!=NULL) { *pNeededToNormalize=FALSE; } if(!(forward ? src->hasNext(src) : src->hasPrevious(src))) { return u_terminateUChars(dest, destCapacity, 0, pErrorCode); } UnicodeString buffer; UChar32 c; if(forward) { /* get one character and ignore its properties */ buffer.append(uiter_next32(src)); /* get all following characters until we see a boundary */ while((c=uiter_next32(src))>=0) { if(n2->hasBoundaryBefore(c)) { /* back out the latest movement to stop at the boundary */ src->move(src, -U16_LENGTH(c), UITER_CURRENT); break; } else { buffer.append(c); } } } else { while((c=uiter_previous32(src))>=0) { /* always write this character to the front of the buffer */ buffer.insert(0, c); /* stop if this just-copied character is a boundary */ if(n2->hasBoundaryBefore(c)) { break; } } } UnicodeString destString(dest, 0, destCapacity); if(buffer.length()>0 && doNormalize) { n2->normalize(buffer, destString, *pErrorCode).extract(dest, destCapacity, *pErrorCode); if(pNeededToNormalize!=NULL && U_SUCCESS(*pErrorCode)) { *pNeededToNormalize= destString!=buffer; } return destString.length(); } else { /* just copy the source characters */ return buffer.extract(dest, destCapacity, *pErrorCode); } }
/** * If in "by digits" mode, fills in the substitution one decimal digit * at a time using the rule set containing this substitution. * Otherwise, uses the superclass function. * @param number The number being formatted * @param toInsertInto The string to insert the result of formatting * the substitution into * @param pos The position of the owning rule's rule text in * toInsertInto */ void FractionalPartSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t _pos) const { // if we're not in "byDigits" mode, just use the inherited // doSubstitution() routine if (!byDigits) { NFSubstitution::doSubstitution(number, toInsertInto, _pos); // if we're in "byDigits" mode, transform the value into an integer // by moving the decimal point eight places to the right and // pulling digits off the right one at a time, formatting each digit // as an integer using this substitution's owning rule set // (this is slower, but more accurate, than doing it from the // other end) } else { // int32_t numberToFormat = (int32_t)uprv_round(transformNumber(number) * uprv_pow(10, kMaxDecimalDigits)); // // this flag keeps us from formatting trailing zeros. It starts // // out false because we're pulling from the right, and switches // // to true the first time we encounter a non-zero digit // UBool doZeros = FALSE; // for (int32_t i = 0; i < kMaxDecimalDigits; i++) { // int64_t digit = numberToFormat % 10; // if (digit != 0 || doZeros) { // if (doZeros && useSpaces) { // toInsertInto.insert(_pos + getPos(), gSpace); // } // doZeros = TRUE; // getRuleSet()->format(digit, toInsertInto, _pos + getPos()); // } // numberToFormat /= 10; // } DigitList dl; dl.set(number); dl.roundFixedPoint(20); // round to 20 fraction digits. dl.reduce(); // Removes any trailing zeros. UBool pad = FALSE; for (int32_t didx = dl.getCount()-1; didx>=dl.getDecimalAt(); didx--) { // Loop iterates over fraction digits, starting with the LSD. // include both real digits from the number, and zeros // to the left of the MSD but to the right of the decimal point. if (pad && useSpaces) { toInsertInto.insert(_pos + getPos(), gSpace); } else { pad = TRUE; } int64_t digit = didx>=0 ? dl.getDigit(didx) - '0' : 0; getRuleSet()->format(digit, toInsertInto, _pos + getPos()); } if (!pad) { // hack around lack of precision in digitlist. if we would end up with // "foo point" make sure we add a " zero" to the end. getRuleSet()->format((int64_t)0, toInsertInto, _pos + getPos()); } } }
void IntlTestRBNFParse::testfmt(RuleBasedNumberFormat* formatter, int val, UErrorCode& status) { UnicodeString us; formatter->format((const Formattable)(int32_t)val, us, status); if (U_SUCCESS(status)) { us.insert(0, (UChar)'"'); us.append((UChar)'"'); logln(us); } else { logln("error: could not format %d, returned status: %d", val, status); } }
void NumeratorSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t apos) const { // perform a transformation on the number being formatted that // is dependent on the type of substitution this is double numberToFormat = transformNumber(number); int64_t longNF = util64_fromDouble(numberToFormat); const NFRuleSet* aruleSet = getRuleSet(); if (withZeros && aruleSet != NULL) { // if there are leading zeros in the decimal expansion then emit them int64_t nf =longNF; int32_t len = toInsertInto.length(); while ((nf *= 10) < denominator) { toInsertInto.insert(apos + getPos(), gSpace); aruleSet->format((int64_t)0, toInsertInto, apos + getPos()); } apos += toInsertInto.length() - len; } // if the result is an integer, from here on out we work in integer // space (saving time and memory and preserving accuracy) if (numberToFormat == longNF && aruleSet != NULL) { aruleSet->format(longNF, toInsertInto, apos + getPos()); // if the result isn't an integer, then call either our rule set's // format() method or our DecimalFormat's format() method to // format the result } else { if (aruleSet != NULL) { aruleSet->format(numberToFormat, toInsertInto, apos + getPos()); } else { UErrorCode status = U_ZERO_ERROR; UnicodeString temp; getNumberFormat()->format(numberToFormat, temp, status); toInsertInto.insert(apos + getPos(), temp); } } }
UnicodeString& StringReplacer::toReplacerPattern(UnicodeString& rule, UBool escapeUnprintable) const { rule.truncate(0); UnicodeString quoteBuf; int32_t cursor = cursorPos; // Handle a cursor preceding the output if (hasCursor && cursor < 0) { while (cursor++ < 0) { ICU_Utility::appendToRule(rule, (UChar)0x0040 /*@*/, TRUE, escapeUnprintable, quoteBuf); } // Fall through and append '|' below } for (int32_t i=0; i<output.length(); ++i) { if (hasCursor && i == cursor) { ICU_Utility::appendToRule(rule, (UChar)0x007C /*|*/, TRUE, escapeUnprintable, quoteBuf); } UChar c = output.charAt(i); // Ok to use 16-bits here UnicodeReplacer* r = data->lookupReplacer(c); if (r == NULL) { ICU_Utility::appendToRule(rule, c, FALSE, escapeUnprintable, quoteBuf); } else { UnicodeString buf; r->toReplacerPattern(buf, escapeUnprintable); buf.insert(0, (UChar)0x20); buf.append((UChar)0x20); ICU_Utility::appendToRule(rule, buf, TRUE, escapeUnprintable, quoteBuf); } } // Handle a cursor after the output. Use > rather than >= because // if cursor == output.length() it is at the end of the output, // which is the default position, so we need not emit it. if (hasCursor && cursor > output.length()) { cursor -= output.length(); while (cursor-- > 0) { ICU_Utility::appendToRule(rule, (UChar)0x0040 /*@*/, TRUE, escapeUnprintable, quoteBuf); } ICU_Utility::appendToRule(rule, (UChar)0x007C /*|*/, TRUE, escapeUnprintable, quoteBuf); } // Flush quoteBuf out to result ICU_Utility::appendToRule(rule, -1, TRUE, escapeUnprintable, quoteBuf); return rule; }
UnicodeString word_wrap(const UnicodeString& message, unsigned wrap_bound) { UnicodeString msg = message; unsigned limit = wrap_bound; unsigned idx = -1; for (unsigned i = 0; i < msg.size(); i++) { if (i >= limit) { if (idx != -1) { msg.insert(idx, '\n'); i = idx + 1; limit = idx + 2 + wrap_bound; idx = -1; continue; } } if (msg[i] == ' ') idx = i; } return msg; }
UnicodeString RegExpManager::Encode(const UnicodeString& regexp) const { UnicodeString result = regexp; int32_t pos = 0; // Replace + with \+ while ((pos = result.indexOf('+', pos)) != -1) { result.insert(pos, '\\'); pos += 2; } // Replace ' ' with + while ((pos = result.indexOf(' ')) != -1) { result.setCharAt(pos, '+'); } return result; }
void TextBox::InsertText( const Gwen::UnicodeString& strInsert ) { // TODO: Make sure fits (implement maxlength) if ( HasSelection() ) { EraseSelection(); } if ( m_iCursorPos > TextLength() ) m_iCursorPos = TextLength(); if ( !IsTextAllowed( strInsert, m_iCursorPos ) ) return; UnicodeString str = GetText(); str.insert( m_iCursorPos, strInsert ); SetText( str ); m_iCursorPos += (int) strInsert.size(); m_iCursorEnd = m_iCursorPos; RefreshCursorBounds(); }
/** * Performs a mathematical operation on the number, formats it using * either ruleSet or decimalFormat, and inserts the result into * toInsertInto. * @param number The number being formatted. * @param toInsertInto The string we insert the result into * @param pos The position in toInsertInto where the owning rule's * rule text begins (this value is added to this substitution's * position to determine exactly where to insert the new text) */ void NFSubstitution::doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t _pos) const { if (ruleSet != NULL) { // perform a transformation on the number that is dependent // on the type of substitution this is, then just call its // rule set's format() method to format the result ruleSet->format(transformNumber(number), toInsertInto, _pos + this->pos); } else if (numberFormat != NULL) { // or perform the transformation on the number (preserving // the result's fractional part if the formatter it set // to show it), then use that formatter's format() method // to format the result double numberToFormat = transformNumber((double)number); if (numberFormat->getMaximumFractionDigits() == 0) { numberToFormat = uprv_floor(numberToFormat); } UnicodeString temp; numberFormat->format(numberToFormat, temp); toInsertInto.insert(_pos + this->pos, temp); } }
/** * Performs a mathematical operation on the number, formats it using * either ruleSet or decimalFormat, and inserts the result into * toInsertInto. * @param number The number being formatted. * @param toInsertInto The string we insert the result into * @param pos The position in toInsertInto where the owning rule's * rule text begins (this value is added to this substitution's * position to determine exactly where to insert the new text) */ void NFSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t _pos) const { // perform a transformation on the number being formatted that // is dependent on the type of substitution this is double numberToFormat = transformNumber(number); // if the result is an integer, from here on out we work in integer // space (saving time and memory and preserving accuracy) if (numberToFormat == uprv_floor(numberToFormat) && ruleSet != NULL) { ruleSet->format(util64_fromDouble(numberToFormat), toInsertInto, _pos + this->pos); // if the result isn't an integer, then call either our rule set's // format() method or our DecimalFormat's format() method to // format the result } else { if (ruleSet != NULL) { ruleSet->format(numberToFormat, toInsertInto, _pos + this->pos); } else if (numberFormat != NULL) { UnicodeString temp; numberFormat->format(numberToFormat, temp); toInsertInto.insert(_pos + this->pos, temp); } } }
void U_EXPORT2 DateIntervalFormat::adjustFieldWidth(const UnicodeString& inputSkeleton, const UnicodeString& bestMatchSkeleton, const UnicodeString& bestIntervalPattern, int8_t differenceInfo, UnicodeString& adjustedPtn) { adjustedPtn = bestIntervalPattern; int32_t inputSkeletonFieldWidth[] = { // A B C D E F G H I J K L M N O 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // P Q R S T U V W X Y Z 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // a b c d e f g h i j k l m n o 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // p q r s t u v w x y z 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int32_t bestMatchSkeletonFieldWidth[] = { // A B C D E F G H I J K L M N O 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // P Q R S T U V W X Y Z 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // a b c d e f g h i j k l m n o 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // p q r s t u v w x y z 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; DateIntervalInfo::parseSkeleton(inputSkeleton, inputSkeletonFieldWidth); DateIntervalInfo::parseSkeleton(bestMatchSkeleton, bestMatchSkeletonFieldWidth); if ( differenceInfo == 2 ) { adjustedPtn.findAndReplace("v", "z"); } UBool inQuote = false; UChar prevCh = 0; int32_t count = 0; const int8_t PATTERN_CHAR_BASE = 0x41; // loop through the pattern string character by character int32_t adjustedPtnLength = adjustedPtn.length(); int32_t i; for (i = 0; i < adjustedPtnLength; ++i) { UChar ch = adjustedPtn.charAt(i); if (ch != prevCh && count > 0) { // check the repeativeness of pattern letter UChar skeletonChar = prevCh; if ( skeletonChar == CAP_L ) { // there is no "L" (always be "M") in skeleton, // but there is "L" in pattern. // for skeleton "M+", the pattern might be "...L..." skeletonChar = CAP_M; } int32_t fieldCount = bestMatchSkeletonFieldWidth[(int)(skeletonChar - PATTERN_CHAR_BASE)]; int32_t inputFieldCount = inputSkeletonFieldWidth[(int)(skeletonChar - PATTERN_CHAR_BASE)]; if ( fieldCount == count && inputFieldCount > fieldCount ) { count = inputFieldCount - fieldCount; int32_t j; for ( j = 0; j < count; ++j ) { adjustedPtn.insert(i, prevCh); } i += count; adjustedPtnLength += count; } count = 0; } if (ch == '\'') { // Consecutive single quotes are a single quote literal, // either outside of quotes or between quotes if ((i+1) < adjustedPtn.length() && adjustedPtn.charAt(i+1) == '\'') { ++i; } else { inQuote = ! inQuote; } } else if ( ! inQuote && ((ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/) || (ch >= 0x0041 /*'A'*/ && ch <= 0x005A /*'Z'*/))) { // ch is a date-time pattern character prevCh = ch; ++count; } } if ( count > 0 ) { // last item // check the repeativeness of pattern letter UChar skeletonChar = prevCh; if ( skeletonChar == CAP_L ) { // there is no "L" (always be "M") in skeleton, // but there is "L" in pattern. // for skeleton "M+", the pattern might be "...L..." skeletonChar = CAP_M; } int32_t fieldCount = bestMatchSkeletonFieldWidth[(int)(skeletonChar - PATTERN_CHAR_BASE)]; int32_t inputFieldCount = inputSkeletonFieldWidth[(int)(skeletonChar - PATTERN_CHAR_BASE)]; if ( fieldCount == count && inputFieldCount > fieldCount ) { count = inputFieldCount - fieldCount; int32_t j; for ( j = 0; j < count; ++j ) { adjustedPtn.append(prevCh); } } } }
/** * Parse a global filter of the form "[f]" or "([f])", depending * on 'withParens'. * @param id the pattern the parse * @param pos INPUT-OUTPUT parameter. On input, the position of * the first character to parse. On output, the position after * the last character parsed. * @param dir the direction. * @param withParens INPUT-OUTPUT parameter. On entry, if * withParens is 0, then parens are disallowed. If it is 1, * then parens are requires. If it is -1, then parens are * optional, and the return result will be set to 0 or 1. * @param canonID OUTPUT parameter. The pattern for the filter * added to the canonID, either at the end, if dir is FORWARD, or * at the start, if dir is REVERSE. The pattern will be enclosed * in parentheses if appropriate, and will be suffixed with an * ID_DELIM character. May be NULL. * @return a UnicodeSet object or NULL. A non-NULL results * indicates a successful parse, regardless of whether the filter * applies to the given direction. The caller should discard it * if withParens != (dir == REVERSE). */ UnicodeSet * TransliteratorIDParser::parseGlobalFilter(const UnicodeString & id, int32_t & pos, int32_t dir, int32_t & withParens, UnicodeString * canonID) { UnicodeSet * filter = NULL; int32_t start = pos; if (withParens == -1) { withParens = ICU_Utility::parseChar(id, pos, OPEN_REV) ? 1 : 0; } else if (withParens == 1) { if (!ICU_Utility::parseChar(id, pos, OPEN_REV)) { pos = start; return NULL; } } ICU_Utility::skipWhitespace(id, pos, TRUE); if (UnicodeSet::resemblesPattern(id, pos)) { ParsePosition ppos(pos); UErrorCode ec = U_ZERO_ERROR; filter = new UnicodeSet(id, ppos, USET_IGNORE_SPACE, NULL, ec); /* test for NULL */ if (filter == 0) { pos = start; return 0; } if (U_FAILURE(ec)) { delete filter; pos = start; return NULL; } UnicodeString pattern; id.extractBetween(pos, ppos.getIndex(), pattern); pos = ppos.getIndex(); if (withParens == 1 && !ICU_Utility::parseChar(id, pos, CLOSE_REV)) { pos = start; return NULL; } // In the forward direction, append the pattern to the // canonID. In the reverse, insert it at zero, and invert // the presence of parens ("A" <-> "(A)"). if (canonID != NULL) { if (dir == FORWARD) { if (withParens == 1) { pattern.insert(0, OPEN_REV); pattern.append(CLOSE_REV); } canonID->append(pattern).append(ID_DELIM); } else { if (withParens == 0) { pattern.insert(0, OPEN_REV); pattern.append(CLOSE_REV); } canonID->insert(0, pattern); canonID->insert(pattern.length(), ID_DELIM); } } } return filter; }
/** * If in "by digits" mode, fills in the substitution one decimal digit * at a time using the rule set containing this substitution. * Otherwise, uses the superclass function. * @param number The number being formatted * @param toInsertInto The string to insert the result of formatting * the substitution into * @param pos The position of the owning rule's rule text in * toInsertInto */ void FractionalPartSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t _pos) const { // if we're not in "byDigits" mode, just use the inherited // doSubstitution() routine if (!byDigits) { NFSubstitution::doSubstitution(number, toInsertInto, _pos); // if we're in "byDigits" mode, transform the value into an integer // by moving the decimal point eight places to the right and // pulling digits off the right one at a time, formatting each digit // as an integer using this substitution's owning rule set // (this is slower, but more accurate, than doing it from the // other end) } else { // int32_t numberToFormat = (int32_t)uprv_round(transformNumber(number) * uprv_pow(10, kMaxDecimalDigits)); // // this flag keeps us from formatting trailing zeros. It starts // // out false because we're pulling from the right, and switches // // to true the first time we encounter a non-zero digit // UBool doZeros = FALSE; // for (int32_t i = 0; i < kMaxDecimalDigits; i++) { // int64_t digit = numberToFormat % 10; // if (digit != 0 || doZeros) { // if (doZeros && useSpaces) { // toInsertInto.insert(_pos + getPos(), gSpace); // } // doZeros = TRUE; // getRuleSet()->format(digit, toInsertInto, _pos + getPos()); // } // numberToFormat /= 10; // } DigitList dl; dl.set(number, 20, TRUE); UBool pad = FALSE; while (dl.fCount > (dl.fDecimalAt <= 0 ? 0 : dl.fDecimalAt)) { if (pad && useSpaces) { toInsertInto.insert(_pos + getPos(), gSpace); } else { pad = TRUE; } getRuleSet()->format((int64_t)(dl.fDigits[--dl.fCount] - '0'), toInsertInto, _pos + getPos()); } while (dl.fDecimalAt < 0) { if (pad && useSpaces) { toInsertInto.insert(_pos + getPos(), gSpace); } else { pad = TRUE; } getRuleSet()->format((int64_t)0, toInsertInto, _pos + getPos()); ++dl.fDecimalAt; } if (!pad) { // hack around lack of precision in digitlist. if we would end up with // "foo point" make sure we add a " zero" to the end. getRuleSet()->format((int64_t)0, toInsertInto, _pos + getPos()); } } }
UnicodeString& RelativeDateFormat::format( Calendar& cal, UnicodeString& appendTo, FieldPosition& pos) const { UErrorCode status = U_ZERO_ERROR; UnicodeString relativeDayString; UDisplayContext capitalizationContext = getContext(UDISPCTX_TYPE_CAPITALIZATION, status); // calculate the difference, in days, between 'cal' and now. int dayDiff = dayDifference(cal, status); // look up string int32_t len = 0; const UChar *theString = getStringForDay(dayDiff, len, status); if(U_SUCCESS(status) && (theString!=NULL)) { // found a relative string relativeDayString.setTo(theString, len); } if ( relativeDayString.length() > 0 && !fDatePattern.isEmpty() && (fTimePattern.isEmpty() || fCombinedFormat == NULL || fCombinedHasDateAtStart)) { #if !UCONFIG_NO_BREAK_ITERATION // capitalize relativeDayString according to context for relative, set formatter no context if ( u_islower(relativeDayString.char32At(0)) && fCapitalizationBrkIter!= NULL && ( capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE || (capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU && fCapitalizationOfRelativeUnitsForUIListMenu) || (capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_STANDALONE && fCapitalizationOfRelativeUnitsForStandAlone) ) ) { // titlecase first word of relativeDayString relativeDayString.toTitle(fCapitalizationBrkIter, fLocale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT); } #endif fDateTimeFormatter->setContext(UDISPCTX_CAPITALIZATION_NONE, status); } else { // set our context for the formatter fDateTimeFormatter->setContext(capitalizationContext, status); } if (fDatePattern.isEmpty()) { fDateTimeFormatter->applyPattern(fTimePattern); fDateTimeFormatter->format(cal,appendTo,pos); } else if (fTimePattern.isEmpty() || fCombinedFormat == NULL) { if (relativeDayString.length() > 0) { appendTo.append(relativeDayString); } else { fDateTimeFormatter->applyPattern(fDatePattern); fDateTimeFormatter->format(cal,appendTo,pos); } } else { UnicodeString datePattern; if (relativeDayString.length() > 0) { // Need to quote the relativeDayString to make it a legal date pattern relativeDayString.findAndReplace(UNICODE_STRING("'", 1), UNICODE_STRING("''", 2)); // double any existing APOSTROPHE relativeDayString.insert(0, APOSTROPHE); // add APOSTROPHE at beginning... relativeDayString.append(APOSTROPHE); // and at end datePattern.setTo(relativeDayString); } else { datePattern.setTo(fDatePattern); } UnicodeString combinedPattern; fCombinedFormat->format(fTimePattern, datePattern, combinedPattern, status); fDateTimeFormatter->applyPattern(combinedPattern); fDateTimeFormatter->format(cal,appendTo,pos); } return appendTo; }
void DateIntervalFormat::initializePattern(UErrorCode& status) { if ( U_FAILURE(status) ) { return; } const Locale& locale = fDateFormat->getSmpFmtLocale(); if ( fSkeleton.isEmpty() ) { UnicodeString fullPattern; fDateFormat->toPattern(fullPattern); #ifdef DTITVFMT_DEBUG char result[1000]; char result_1[1000]; char mesg[2000]; fSkeleton.extract(0, fSkeleton.length(), result, "UTF-8"); sprintf(mesg, "in getBestSkeleton: fSkeleton: %s; \n", result); PRINTMESG(mesg) #endif // fSkeleton is already set by createDateIntervalInstance() // or by createInstance(UnicodeString skeleton, .... ) fSkeleton = fDtpng->getSkeleton(fullPattern, status); if ( U_FAILURE(status) ) { return; } } // initialize the fIntervalPattern ordering int8_t i; for ( i = 0; i < DateIntervalInfo::kIPI_MAX_INDEX; ++i ) { fIntervalPatterns[i].laterDateFirst = fInfo->getDefaultOrder(); } /* Check whether the skeleton is a combination of date and time. * For the complication reason 1 explained above. */ UnicodeString dateSkeleton; UnicodeString timeSkeleton; UnicodeString normalizedTimeSkeleton; UnicodeString normalizedDateSkeleton; /* the difference between time skeleton and normalizedTimeSkeleton are: * 1. (Formerly, normalized time skeleton folded 'H' to 'h'; no longer true) * 2. 'a' is omitted in normalized time skeleton. * 3. there is only one appearance for 'h' or 'H', 'm','v', 'z' in normalized * time skeleton * * The difference between date skeleton and normalizedDateSkeleton are: * 1. both 'y' and 'd' appear only once in normalizeDateSkeleton * 2. 'E' and 'EE' are normalized into 'EEE' * 3. 'MM' is normalized into 'M' */ getDateTimeSkeleton(fSkeleton, dateSkeleton, normalizedDateSkeleton, timeSkeleton, normalizedTimeSkeleton); #ifdef DTITVFMT_DEBUG char result[1000]; char result_1[1000]; char mesg[2000]; fSkeleton.extract(0, fSkeleton.length(), result, "UTF-8"); sprintf(mesg, "in getBestSkeleton: fSkeleton: %s; \n", result); PRINTMESG(mesg) #endif UBool found = setSeparateDateTimePtn(normalizedDateSkeleton, normalizedTimeSkeleton); if ( found == false ) { // use fallback // TODO: if user asks "m"(minute), but "d"(day) differ if ( timeSkeleton.length() != 0 ) { if ( dateSkeleton.length() == 0 ) { // prefix with yMd timeSkeleton.insert(0, gDateFormatSkeleton[DateFormat::kShort]); UnicodeString pattern = fDtpng->getBestPattern(timeSkeleton, status); if ( U_FAILURE(status) ) { return; } // for fall back interval patterns, // the first part of the pattern is empty, // the second part of the pattern is the full-pattern // should be used in fall-back. setPatternInfo(UCAL_DATE, NULL, &pattern, fInfo->getDefaultOrder()); setPatternInfo(UCAL_MONTH, NULL, &pattern, fInfo->getDefaultOrder()); setPatternInfo(UCAL_YEAR, NULL, &pattern, fInfo->getDefaultOrder()); } else { // TODO: fall back } } else { // TODO: fall back } return; } // end of skeleton not found // interval patterns for skeleton are found in resource if ( timeSkeleton.length() == 0 ) { // done } else if ( dateSkeleton.length() == 0 ) { // prefix with yMd timeSkeleton.insert(0, gDateFormatSkeleton[DateFormat::kShort]); UnicodeString pattern = fDtpng->getBestPattern(timeSkeleton, status); if ( U_FAILURE(status) ) { return; } // for fall back interval patterns, // the first part of the pattern is empty, // the second part of the pattern is the full-pattern // should be used in fall-back. setPatternInfo(UCAL_DATE, NULL, &pattern, fInfo->getDefaultOrder()); setPatternInfo(UCAL_MONTH, NULL, &pattern, fInfo->getDefaultOrder()); setPatternInfo(UCAL_YEAR, NULL, &pattern, fInfo->getDefaultOrder()); } else { /* if both present, * 1) when the year, month, or day differs, * concatenate the two original expressions with a separator between, * 2) otherwise, present the date followed by the * range expression for the time. */ /* * 1) when the year, month, or day differs, * concatenate the two original expressions with a separator between, */ // if field exists, use fall back UnicodeString skeleton = fSkeleton; if ( !fieldExistsInSkeleton(UCAL_DATE, dateSkeleton) ) { // prefix skeleton with 'd' skeleton.insert(0, LOW_D); setFallbackPattern(UCAL_DATE, skeleton, status); } if ( !fieldExistsInSkeleton(UCAL_MONTH, dateSkeleton) ) { // then prefix skeleton with 'M' skeleton.insert(0, CAP_M); setFallbackPattern(UCAL_MONTH, skeleton, status); } if ( !fieldExistsInSkeleton(UCAL_YEAR, dateSkeleton) ) { // then prefix skeleton with 'y' skeleton.insert(0, LOW_Y); setFallbackPattern(UCAL_YEAR, skeleton, status); } /* * 2) otherwise, present the date followed by the * range expression for the time. */ // Need the Date/Time pattern for concatnation the date with // the time interval. // The date/time pattern ( such as {0} {1} ) is saved in // calendar, that is why need to get the CalendarData here. CalendarData* calData = new CalendarData(locale, NULL, status); if ( U_FAILURE(status) ) { delete calData; return; } if ( calData == NULL ) { status = U_MEMORY_ALLOCATION_ERROR; return; } const UResourceBundle* dateTimePatternsRes = calData->getByKey( gDateTimePatternsTag, status); int32_t dateTimeFormatLength; const UChar* dateTimeFormat = ures_getStringByIndex( dateTimePatternsRes, (int32_t)DateFormat::kDateTime, &dateTimeFormatLength, &status); if ( U_FAILURE(status) ) { return; } UnicodeString datePattern = fDtpng->getBestPattern(dateSkeleton, status); concatSingleDate2TimeInterval(dateTimeFormat, dateTimeFormatLength, datePattern, UCAL_AM_PM, status); concatSingleDate2TimeInterval(dateTimeFormat, dateTimeFormatLength, datePattern, UCAL_HOUR, status); concatSingleDate2TimeInterval(dateTimeFormat, dateTimeFormatLength, datePattern, UCAL_MINUTE, status); delete calData; } }