StandardPlural::Form QuantityFormatter::selectPlural( const Formattable &number, const NumberFormat &fmt, const PluralRules &rules, UnicodeString &formattedNumber, FieldPosition &pos, UErrorCode &status) { if (U_FAILURE(status)) { return StandardPlural::OTHER; } UnicodeString pluralKeyword; const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(&fmt); if (decFmt != NULL) { number::impl::DecimalQuantity dq; decFmt->formatToDecimalQuantity(number, dq, status); if (U_FAILURE(status)) { return StandardPlural::OTHER; } pluralKeyword = rules.select(dq); decFmt->format(number, formattedNumber, pos, status); } else { if (number.getType() == Formattable::kDouble) { pluralKeyword = rules.select(number.getDouble()); } else if (number.getType() == Formattable::kLong) { pluralKeyword = rules.select(number.getLong()); } else if (number.getType() == Formattable::kInt64) { pluralKeyword = rules.select((double) number.getInt64()); } else { status = U_ILLEGAL_ARGUMENT_ERROR; return StandardPlural::OTHER; } fmt.format(number, formattedNumber, pos, status); } return StandardPlural::orOtherFromString(pluralKeyword); }
void RuleBasedNumberFormat::parse(const UnicodeString& text, Formattable& result, ParsePosition& parsePosition) const { //TODO: We need a real fix. See #6895 / #6896 if (noParse) { // skip parsing parsePosition.setErrorIndex(0); return; } if (!ruleSets) { parsePosition.setErrorIndex(0); return; } UnicodeString workingText(text, parsePosition.getIndex()); ParsePosition workingPos(0); ParsePosition high_pp(0); Formattable high_result; for (NFRuleSet** p = ruleSets; *p; ++p) { NFRuleSet *rp = *p; if (rp->isPublic() && rp->isParseable()) { ParsePosition working_pp(0); Formattable working_result; rp->parse(workingText, working_pp, kMaxDouble, working_result); if (working_pp.getIndex() > high_pp.getIndex()) { high_pp = working_pp; high_result = working_result; if (high_pp.getIndex() == workingText.length()) { break; } } } } int32_t startIndex = parsePosition.getIndex(); parsePosition.setIndex(startIndex + high_pp.getIndex()); if (high_pp.getIndex() > 0) { parsePosition.setErrorIndex(-1); } else { int32_t errorIndex = (high_pp.getErrorIndex()>0)? high_pp.getErrorIndex(): 0; parsePosition.setErrorIndex(startIndex + errorIndex); } result = high_result; if (result.getType() == Formattable::kDouble) { int32_t r = (int32_t)result.getDouble(); if ((double)r == result.getDouble()) { result.setLong(r); } } }
static jobject NativeDecimalFormat_parse(JNIEnv* env, jclass, jlong addr, jstring text, jobject position, jboolean parseBigDecimal) { static jmethodID gPP_getIndex = env->GetMethodID(JniConstants::parsePositionClass, "getIndex", "()I"); static jmethodID gPP_setIndex = env->GetMethodID(JniConstants::parsePositionClass, "setIndex", "(I)V"); static jmethodID gPP_setErrorIndex = env->GetMethodID(JniConstants::parsePositionClass, "setErrorIndex", "(I)V"); ScopedJavaUnicodeString src(env, text); if (!src.valid()) { return NULL; } // make sure the ParsePosition is valid. Actually icu4c would parse a number // correctly even if the parsePosition is set to -1, but since the RI fails // for that case we have to fail too int parsePos = env->CallIntMethod(position, gPP_getIndex, NULL); if (parsePos < 0 || parsePos > env->GetStringLength(text)) { return NULL; } Formattable res; ParsePosition pp(parsePos); DecimalFormat* fmt = toDecimalFormat(addr); fmt->parse(src.unicodeString(), res, pp); if (pp.getErrorIndex() == -1) { env->CallVoidMethod(position, gPP_setIndex, pp.getIndex()); } else { env->CallVoidMethod(position, gPP_setErrorIndex, pp.getErrorIndex()); return NULL; } if (parseBigDecimal) { UErrorCode status = U_ZERO_ERROR; StringPiece str = res.getDecimalNumber(status); if (U_SUCCESS(status)) { int len = str.length(); const char* data = str.data(); if (strncmp(data, "NaN", 3) == 0 || strncmp(data, "Inf", 3) == 0 || strncmp(data, "-Inf", 4) == 0) { double resultDouble = res.getDouble(status); return doubleValueOf(env, resultDouble); } return newBigDecimal(env, data, len); } return NULL; } switch (res.getType()) { case Formattable::kDouble: return doubleValueOf(env, res.getDouble()); case Formattable::kLong: return longValueOf(env, res.getLong()); case Formattable::kInt64: return longValueOf(env, res.getInt64()); default: return NULL; } }
void FormattableStreamer::streamOut(ostream& stream, const Formattable& obj) { static DateFormat *defDateFormat = 0; UnicodeString buffer; switch(obj.getType()) { case Formattable::kDate : // Creates a DateFormat instance for formatting the // Date instance. if (defDateFormat == 0) { defDateFormat = DateFormat::createInstance(); } defDateFormat->format(obj.getDate(), buffer); stream << buffer; break; case Formattable::kDouble : // Output the double as is. stream << obj.getDouble() << 'D'; break; case Formattable::kLong : // Output the double as is. stream << obj.getLong() << 'L'; break; case Formattable::kString: // Output the double as is. Please see UnicodeString console // I/O routine for more details. stream << '"' << obj.getString(buffer) << '"'; break; case Formattable::kArray: int32_t i, count; const Formattable* array; array = obj.getArray(count); stream << '['; // Recursively calling the console I/O routine for each element in the array. for (i=0; i<count; ++i) { FormattableStreamer::streamOut(stream, array[i]); stream << ( (i==(count-1)) ? "" : ", " ); } stream << ']'; break; default: // Not a recognizable Formattable object. stream << "INVALID_Formattable"; } stream.flush(); }
U_CAPI double U_EXPORT2 unum_parseDoubleCurrency(const UNumberFormat* fmt, const UChar* text, int32_t textLength, int32_t* parsePos, /* 0 = start */ UChar* currency, UErrorCode* status) { Formattable res; parseRes(res, fmt, text, textLength, parsePos, TRUE, status); currency[0] = 0; if (res.getType() == Formattable::kObject && res.getObject()->getDynamicClassID() == CurrencyAmount::getStaticClassID()) { const CurrencyAmount* c = (const CurrencyAmount*) res.getObject(); u_strcpy(currency, c->getISOCurrency()); } return res.getDouble(*status); }
U_CAPI double U_EXPORT2 unum_parseDoubleCurrency(const UNumberFormat* fmt, const UChar* text, int32_t textLength, int32_t* parsePos, /* 0 = start */ UChar* currency, UErrorCode* status) { Formattable res; parseRes(res, fmt, text, textLength, parsePos, TRUE, status); currency[0] = 0; const CurrencyAmount* c; if (res.getType() == Formattable::kObject && (c = dynamic_cast<const CurrencyAmount*>(res.getObject())) != NULL) { u_strcpy(currency, c->getISOCurrency()); } return res.getDouble(*status); }
U_DRAFT const UChar* U_EXPORT2 ufmt_getUChars(UFormattable *fmt, int32_t *len, UErrorCode *status) { Formattable *obj = Formattable::fromUFormattable(fmt); // avoid bogosity by checking the type first. if( obj->getType() != Formattable::kString ) { if( U_SUCCESS(*status) ){ *status = U_INVALID_FORMAT_ERROR; } return NULL; } // This should return a valid string UnicodeString &str = obj->getString(*status); if( U_SUCCESS(*status) && len != NULL ) { *len = str.length(); } return str.getTerminatedBuffer(); }
void DecimalFormatTest::execParseTest(int32_t lineNum, const UnicodeString &inputText, const UnicodeString &expectedType, const UnicodeString &expectedDecimal, UErrorCode &status) { if (U_FAILURE(status)) { return; } DecimalFormatSymbols symbols(Locale::getUS(), status); UnicodeString pattern = UNICODE_STRING_SIMPLE("####"); DecimalFormat format(pattern, symbols, status); Formattable result; if (U_FAILURE(status)) { errln("file dcfmtest.txt, line %d: %s error creating the formatter.", lineNum, u_errorName(status)); return; } ParsePosition pos; int32_t expectedParseEndPosition = inputText.length(); format.parse(inputText, result, pos); if (expectedParseEndPosition != pos.getIndex()) { errln("file dcfmtest.txt, line %d: Expected parse position afeter parsing: %d. " "Actual parse position: %d", expectedParseEndPosition, pos.getIndex()); return; } char expectedTypeC[2]; expectedType.extract(0, 1, expectedTypeC, 2, US_INV); Formattable::Type expectType = Formattable::kDate; switch (expectedTypeC[0]) { case 'd': expectType = Formattable::kDouble; break; case 'i': expectType = Formattable::kLong; break; case 'l': expectType = Formattable::kInt64; break; default: errln("file dcfmtest.tx, line %d: unrecongized expected type \"%s\"", lineNum, InvariantStringPiece(expectedType).data()); return; } if (result.getType() != expectType) { errln("file dcfmtest.txt, line %d: expectedParseType(%s) != actual parseType(%s)", lineNum, formattableType(expectType), formattableType(result.getType())); return; } StringPiece decimalResult = result.getDecimalNumber(status); if (U_FAILURE(status)) { errln("File %s, line %d: error %s. Line in file dcfmtest.txt: %d:", __FILE__, __LINE__, u_errorName(status), lineNum); return; } InvariantStringPiece expectedResults(expectedDecimal); if (decimalResult != expectedResults) { errln("file dcfmtest.txt, line %d: expected \"%s\", got \"%s\"", lineNum, expectedResults.data(), decimalResult.data()); } return; }
void RbnfRoundTripTest::doTest(const RuleBasedNumberFormat* formatter, double lowLimit, double highLimit) { char buf[128]; uint32_t count = 0; double increment = 1; for (double i = lowLimit; i <= highLimit; i += increment) { if (count % 1000 == 0) { sprintf(buf, "%.12g", i); logln(buf); } if (fabs(i) < 5000) increment = 1; else if (fabs(i) < 500000) increment = 2737; else increment = 267437; UnicodeString formatResult; formatter->format(i, formatResult); UErrorCode status = U_ZERO_ERROR; Formattable parseResult; formatter->parse(formatResult, parseResult, status); if (U_FAILURE(status)) { sprintf(buf, "Round-trip status failure: %.12g, status: %d", i, status); errln(buf); return; } else { double rt = (parseResult.getType() == Formattable::kDouble) ? parseResult.getDouble() : (double)parseResult.getLong(); if (rt != i) { sprintf(buf, "Round-trip failed: %.12g -> %.12g", i, rt); errln(buf); return; } } ++count; } if (lowLimit < 0) { double d = 1.234; while (d < 1000) { UnicodeString formatResult; formatter->format(d, formatResult); UErrorCode status = U_ZERO_ERROR; Formattable parseResult; formatter->parse(formatResult, parseResult, status); if (U_FAILURE(status)) { sprintf(buf, "Round-trip status failure: %.12g, status: %d", d, status); errln(buf); return; } else { double rt = (parseResult.getType() == Formattable::kDouble) ? parseResult.getDouble() : (double)parseResult.getLong(); if (rt != d) { UnicodeString msg; sprintf(buf, "Round-trip failed: %.12g -> ", d); msg.append(buf); msg.append(formatResult); sprintf(buf, " -> %.12g", rt); msg.append(buf); errln(msg); return; } } d *= 10; } } }
void TestChoiceFormat::TestComplexExample( void ) { UErrorCode status = U_ZERO_ERROR; const double filelimits[] = {-1, 0,1,2}; const UnicodeString filepart[] = {"are corrupted files", "are no files","is one file","are {2} files"}; ChoiceFormat* fileform = new ChoiceFormat( filelimits, filepart, 4); if (!fileform) { it_errln("*** test_complex_example fileform"); return; } Format* filenumform = NumberFormat::createInstance( status ); if (!filenumform) { dataerrln((UnicodeString)"*** test_complex_example filenumform - " + u_errorName(status)); delete fileform; return; } if (!chkstatus( status, "*** test_simple_example filenumform" )) { delete fileform; delete filenumform; return; } //const Format* testFormats[] = { fileform, NULL, filenumform }; //pattform->setFormats( testFormats, 3 ); MessageFormat* pattform = new MessageFormat("There {0} on {1}", status ); if (!pattform) { it_errln("*** test_complex_example pattform"); delete fileform; delete filenumform; return; } if (!chkstatus( status, "*** test_complex_example pattform" )) { delete fileform; delete filenumform; delete pattform; return; } pattform->setFormat( 0, *fileform ); pattform->setFormat( 2, *filenumform ); Formattable testArgs[] = {(int32_t)0, "Disk_A", (int32_t)0}; UnicodeString str; UnicodeString res1, res2; pattform->toPattern( res1 ); it_logln("MessageFormat toPattern: " + res1); fileform->toPattern( res1 ); it_logln("ChoiceFormat toPattern: " + res1); if (res1 == "-1#are corrupted files|0#are no files|1#is one file|2#are {2} files") { it_logln("toPattern tested!"); }else{ it_errln("*** ChoiceFormat to Pattern result!"); } FieldPosition fpos(FieldPosition::DONT_CARE); UnicodeString checkstr[] = { "There are corrupted files on Disk_A", "There are no files on Disk_A", "There is one file on Disk_A", "There are 2 files on Disk_A", "There are 3 files on Disk_A" }; // if (status != U_ZERO_ERROR) return; // TODO: analyze why we have such a bad bail out here! if (U_FAILURE(status)) { delete fileform; delete filenumform; delete pattform; return; } int32_t i; int32_t start = -1; for (i = start; i < 4; ++i) { str = ""; status = U_ZERO_ERROR; testArgs[0] = Formattable((int32_t)i); testArgs[2] = testArgs[0]; res2 = pattform->format(testArgs, 3, str, fpos, status ); if (!chkstatus( status, "*** test_complex_example format" )) { delete fileform; delete filenumform; delete pattform; return; } it_logln(i + UnicodeString(" -> ") + res2); if (res2 != checkstr[i - start]) { it_errln("*** test_complex_example res string"); it_errln(UnicodeString("*** ") + i + UnicodeString(" -> '") + res2 + UnicodeString("' unlike '") + checkstr[i] + UnicodeString("' ! ")); } } it_logln(); it_logln("------ additional testing in complex test ------"); it_logln(); // #if 0 // ICU 4.8 deprecates and disables the ChoiceFormat getters. int32_t retCount; const double* retLimits = fileform->getLimits( retCount ); if ((retCount == 4) && (retLimits) && (retLimits[0] == -1.0) && (retLimits[1] == 0.0) && (retLimits[2] == 1.0) && (retLimits[3] == 2.0)) { it_logln("getLimits tested!"); }else{ it_errln("*** getLimits unexpected result!"); } const UnicodeString* retFormats = fileform->getFormats( retCount ); if ((retCount == 4) && (retFormats) && (retFormats[0] == "are corrupted files") && (retFormats[1] == "are no files") && (retFormats[2] == "is one file") && (retFormats[3] == "are {2} files")) { it_logln("getFormats tested!"); }else{ it_errln("*** getFormats unexpected result!"); } #endif UnicodeString checkstr2[] = { "There is no folder on Disk_A", "There is one folder on Disk_A", "There are many folders on Disk_A", "There are many folders on Disk_A" }; fileform->applyPattern("0#is no folder|1#is one folder|2#are many folders", status ); if (status == U_ZERO_ERROR) it_logln("status applyPattern OK!"); if (!chkstatus( status, "*** test_complex_example pattform" )) { delete fileform; delete filenumform; delete pattform; return; } pattform->setFormat( 0, *fileform ); fpos = 0; for (i = 0; i < 4; ++i) { str = ""; status = U_ZERO_ERROR; testArgs[0] = Formattable((int32_t)i); testArgs[2] = testArgs[0]; res2 = pattform->format(testArgs, 3, str, fpos, status ); if (!chkstatus( status, "*** test_complex_example format 2" )) { delete fileform; delete filenumform; delete pattform; return; } it_logln(UnicodeString() + i + UnicodeString(" -> ") + res2); if (res2 != checkstr2[i]) { it_errln("*** test_complex_example res string"); it_errln(UnicodeString("*** ") + i + UnicodeString(" -> '") + res2 + UnicodeString("' unlike '") + checkstr2[i] + UnicodeString("' ! ")); } } const double limits_A[] = {1,2,3,4,5,6,7}; const UnicodeString monthNames_A[] = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"}; ChoiceFormat* form_A = new ChoiceFormat(limits_A, monthNames_A, 7); ChoiceFormat* form_A2 = new ChoiceFormat(limits_A, monthNames_A, 7); const double limits_B[] = {1,2,3,4,5,6,7}; const UnicodeString monthNames_B[] = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat_BBB"}; ChoiceFormat* form_B = new ChoiceFormat(limits_B, monthNames_B, 7); if (!form_A || !form_B || !form_A2) { it_errln("*** test-choiceFormat not allocatable!"); }else{ if (*form_A == *form_A2) { it_logln("operator== tested."); }else{ it_errln("*** operator=="); } if (*form_A != *form_B) { it_logln("operator!= tested."); }else{ it_errln("*** operator!="); } ChoiceFormat* form_A3 = (ChoiceFormat*) form_A->clone(); if (!form_A3) { it_errln("*** ChoiceFormat->clone is nil."); }else{ if ((*form_A3 == *form_A) && (*form_A3 != *form_B)) { it_logln("method clone tested."); }else{ it_errln("*** ChoiceFormat clone or operator==, or operator!= ."); } } ChoiceFormat form_Assigned( *form_A ); UBool ok = (form_Assigned == *form_A) && (form_Assigned != *form_B); form_Assigned = *form_B; ok = ok && (form_Assigned != *form_A) && (form_Assigned == *form_B); if (ok) { it_logln("copy constructor and operator= tested."); }else{ it_errln("*** copy constructor or operator= or operator == or operator != ."); } delete form_A3; } delete form_A; delete form_A2; delete form_B; const char* testPattern = "0#none|1#one|2#many"; ChoiceFormat form_pat( testPattern, status ); if (!chkstatus( status, "*** ChoiceFormat contructor( newPattern, status)" )) { delete fileform; delete filenumform; delete pattform; return; } form_pat.toPattern( res1 ); if (res1 == "0#none|1#one|2#many") { it_logln("ChoiceFormat contructor( newPattern, status) tested"); }else{ it_errln("*** ChoiceFormat contructor( newPattern, status) or toPattern result!"); } double d_a2[] = { 3.0, 4.0 }; UnicodeString s_a2[] = { "third", "forth" }; form_pat.setChoices( d_a2, s_a2, 2 ); form_pat.toPattern( res1 ); it_logln(UnicodeString("ChoiceFormat adoptChoices toPattern: ") + res1); if (res1 == "3#third|4#forth") { it_logln("ChoiceFormat adoptChoices tested"); }else{ it_errln("*** ChoiceFormat adoptChoices result!"); } str = ""; fpos = 0; status = U_ZERO_ERROR; double arg_double = 3.0; res1 = form_pat.format( arg_double, str, fpos ); it_logln(UnicodeString("ChoiceFormat format:") + res1); if (res1 != "third") it_errln("*** ChoiceFormat format (double, ...) result!"); str = ""; fpos = 0; status = U_ZERO_ERROR; int64_t arg_64 = 3; res1 = form_pat.format( arg_64, str, fpos ); it_logln(UnicodeString("ChoiceFormat format:") + res1); if (res1 != "third") it_errln("*** ChoiceFormat format (int64_t, ...) result!"); str = ""; fpos = 0; status = U_ZERO_ERROR; int32_t arg_long = 3; res1 = form_pat.format( arg_long, str, fpos ); it_logln(UnicodeString("ChoiceFormat format:") + res1); if (res1 != "third") it_errln("*** ChoiceFormat format (int32_t, ...) result!"); Formattable ft( (int32_t)3 ); str = ""; fpos = 0; status = U_ZERO_ERROR; res1 = form_pat.format( ft, str, fpos, status ); if (!chkstatus( status, "*** test_complex_example format (int32_t, ...)" )) { delete fileform; delete filenumform; delete pattform; return; } it_logln(UnicodeString("ChoiceFormat format:") + res1); if (res1 != "third") it_errln("*** ChoiceFormat format (Formattable, ...) result!"); Formattable fta[] = { (int32_t)3 }; str = ""; fpos = 0; status = U_ZERO_ERROR; res1 = form_pat.format( fta, 1, str, fpos, status ); if (!chkstatus( status, "*** test_complex_example format (int32_t, ...)" )) { delete fileform; delete filenumform; delete pattform; return; } it_logln(UnicodeString("ChoiceFormat format:") + res1); if (res1 != "third") it_errln("*** ChoiceFormat format (Formattable[], cnt, ...) result!"); ParsePosition parse_pos = 0; Formattable result; UnicodeString parsetext("third"); form_pat.parse( parsetext, result, parse_pos ); double rd = (result.getType() == Formattable::kLong) ? result.getLong() : result.getDouble(); if (rd == 3.0) { it_logln("parse( ..., ParsePos ) tested."); }else{ it_errln("*** ChoiceFormat parse( ..., ParsePos )!"); } form_pat.parse( parsetext, result, status ); rd = (result.getType() == Formattable::kLong) ? result.getLong() : result.getDouble(); if (rd == 3.0) { it_logln("parse( ..., UErrorCode ) tested."); }else{ it_errln("*** ChoiceFormat parse( ..., UErrorCode )!"); } /* UClassID classID = ChoiceFormat::getStaticClassID(); if (classID == form_pat.getDynamicClassID()) { it_out << "getStaticClassID and getDynamicClassID tested." << endl; }else{ it_errln("*** getStaticClassID and getDynamicClassID!"); } */ it_logln(); delete fileform; delete filenumform; delete pattform; }
void test_Formattable( void ) { UErrorCode status = U_ZERO_ERROR; Formattable* ftp = new Formattable(); if (!ftp || !(ftp->getType() == Formattable::kLong) || !(ftp->getLong() == 0)) { it_errln("*** Formattable constructor or getType or getLong"); } delete ftp; Formattable fta, ftb; fta.setLong(1); ftb.setLong(2); if ((fta != ftb) || !(fta == ftb)) { it_logln("FT setLong, operator== and operator!= tested."); status = U_ZERO_ERROR; fta.getLong(&status); if ( status == U_INVALID_FORMAT_ERROR){ it_errln("*** FT getLong(UErrorCode* status) failed on real Long"); } else { it_logln("FT getLong(UErrorCode* status) tested."); } }else{ it_errln("*** Formattable setLong or operator== or !="); } fta = ftb; if ((fta == ftb) || !(fta != ftb)) { it_logln("FT operator= tested."); }else{ it_errln("*** FT operator= or operator== or operator!="); } fta.setDouble( 3.0 ); if ((fta.getType() == Formattable::kDouble) && (fta.getDouble() == 3.0)) { it_logln("FT set- and getDouble tested."); }else{ it_errln("*** FT set- or getDouble"); } fta.getDate(status = U_ZERO_ERROR); if (status != U_INVALID_FORMAT_ERROR){ it_errln("*** FT getDate with status should fail on non-Date"); } fta.setDate( 4.0 ); if ((fta.getType() == Formattable::kDate) && (fta.getDate() == 4.0)) { it_logln("FT set- and getDate tested."); status = U_ZERO_ERROR; fta.getDate(status); if ( status == U_INVALID_FORMAT_ERROR){ it_errln("*** FT getDate with status failed on real Date"); } else { it_logln("FT getDate with status tested."); } }else{ it_errln("*** FT set- or getDate"); } status = U_ZERO_ERROR; fta.getLong(&status); if (status != U_INVALID_FORMAT_ERROR){ it_errln("*** FT getLong(UErrorCode* status) should fail on non-Long"); } fta.setString("abc"); const Formattable ftc(fta); UnicodeString res; { UBool t; t = (fta.getType() == Formattable::kString) && (fta.getString(res) == "abc") && (fta.getString() == "abc"); res = fta.getString(status = U_ZERO_ERROR); t = t && (status != U_INVALID_FORMAT_ERROR && res == "abc"); res = ftc.getString(status = U_ZERO_ERROR); t = t && (status != U_INVALID_FORMAT_ERROR && res == "abc"); ftc.getString(res,status = U_ZERO_ERROR); t = t && (status != U_INVALID_FORMAT_ERROR && res == "abc"); if (t) { it_logln("FT set- and getString tested."); }else{ it_errln("*** FT set- or getString"); } } UnicodeString ucs = "unicode-string"; UnicodeString* ucs_ptr = new UnicodeString("pointed-to-unicode-string"); const Formattable ftarray[] = { Formattable( 1.0, Formattable::kIsDate ), 2.0, (int32_t)3, ucs, ucs_ptr }; const int32_t ft_cnt = UPRV_LENGTHOF(ftarray); Formattable ft_arr( ftarray, ft_cnt ); UnicodeString temp; if ((ft_arr[0].getType() == Formattable::kDate) && (ft_arr[0].getDate() == 1.0) && (ft_arr[1].getType() == Formattable::kDouble) && (ft_arr[1].getDouble() == 2.0) && (ft_arr[2].getType() == Formattable::kLong) && (ft_arr[2].getLong() == (int32_t)3) && (ft_arr[3].getType() == Formattable::kString) && (ft_arr[3].getString(temp) == ucs) && (ft_arr[4].getType() == Formattable::kString) && (ft_arr[4].getString(temp) == *ucs_ptr) ) { it_logln("FT constr. for date, double, long, ustring, ustring* and array tested"); }else{ it_errln("*** FT constr. for date, double, long, ustring, ustring* or array"); } int32_t i, res_cnt; const Formattable* res_array = ft_arr.getArray( res_cnt ); if (res_cnt == ft_cnt) { UBool same = TRUE; for (i = 0; i < res_cnt; i++ ) { if (res_array[i] != ftarray[i]) { same = FALSE; } } if (same) { it_logln("FT getArray tested"); res_array = ft_arr.getArray( res_cnt, status = U_ZERO_ERROR); if (status == U_INVALID_FORMAT_ERROR){ it_errln("*** FT getArray with status failed on real array"); } else { it_logln("FT getArray with status tested on real array"); } }else{ it_errln("*** FT getArray comparison"); } }else{ it_errln(UnicodeString("*** FT getArray count res_cnt=") + res_cnt + UnicodeString("ft_cnt=") + ft_cnt); } res_array = fta.getArray(res_cnt, status = U_ZERO_ERROR); if (status == U_INVALID_FORMAT_ERROR){ if (res_cnt == 0 && res_array == NULL){ it_logln("FT getArray with status tested on non array"); } else { it_errln("*** FT getArray with status return values are not consistent"); } } else { it_errln("*** FT getArray with status should fail on non-array"); } Formattable *pf; for(i = 0; i < ft_cnt; ++i) { pf = ftarray[i].clone(); if(pf == (ftarray + i) || *pf != ftarray[i]) { it_errln(UnicodeString("Formattable.clone() failed for item ") + i); } delete pf; } const Formattable ftarr1[] = { Formattable( (int32_t)1 ), Formattable( (int32_t)2 ) }; const Formattable ftarr2[] = { Formattable( (int32_t)3 ), Formattable( (int32_t)4 ) }; const int32_t ftarr1_cnt = (int32_t)(sizeof(ftarr1) / sizeof(Formattable)); const int32_t ftarr2_cnt = (int32_t)(sizeof(ftarr2) / sizeof(Formattable)); ft_arr.setArray( ftarr1, ftarr1_cnt ); if ((ft_arr[0].getType() == Formattable::kLong) && (ft_arr[0].getLong() == (int32_t)1)) { it_logln("FT setArray tested"); }else{ it_errln("*** FT setArray"); } Formattable* ft_dynarr = new Formattable[ftarr2_cnt]; for (i = 0; i < ftarr2_cnt; i++ ) { ft_dynarr[i] = ftarr2[i]; } if ((ft_dynarr[0].getType() == Formattable::kLong) && (ft_dynarr[0].getLong() == (int32_t)3) && (ft_dynarr[1].getType() == Formattable::kLong) && (ft_dynarr[1].getLong() == (int32_t)4)) { it_logln("FT operator= and array operations tested"); }else{ it_errln("*** FT operator= or array operations"); } ft_arr.adoptArray( ft_dynarr, ftarr2_cnt ); if ((ft_arr[0].getType() == Formattable::kLong) && (ft_arr[0].getLong() == (int32_t)3) && (ft_arr[1].getType() == Formattable::kLong) && (ft_arr[1].getLong() == (int32_t)4)) { it_logln("FT adoptArray tested"); }else{ it_errln("*** FT adoptArray or operator[]"); } ft_arr.setLong(0); // calls 'dispose' and deletes adopted array ! UnicodeString* ucs_dyn = new UnicodeString("ttt"); UnicodeString tmp2; fta.adoptString( ucs_dyn ); if ((fta.getType() == Formattable::kString) && (fta.getString(tmp2) == "ttt")) { it_logln("FT adoptString tested"); }else{ it_errln("*** FT adoptString or getString"); } fta.setLong(0); // calls 'dispose' and deletes adopted string ! it_logln(); }
void NumberFormatRoundTripTest::test(NumberFormat *fmt, const Formattable& value) { fmt->setMaximumFractionDigits(999); DecimalFormat *df = dynamic_cast<DecimalFormat *>(fmt); if(df != NULL) { df->setRoundingIncrement(0.0); } UErrorCode status = U_ZERO_ERROR; UnicodeString s, s2, temp; if(isDouble(value)) s = fmt->format(value.getDouble(), s); else s = fmt->format(value.getLong(), s); Formattable n; UBool show = verbose; if(DEBUG_VAR) logln(/*value.getString(temp) +*/ " F> " + escape(s)); fmt->parse(s, n, status); failure(status, "fmt->parse"); if(DEBUG_VAR) logln(escape(s) + " P> " /*+ n.getString(temp)*/); if(isDouble(n)) s2 = fmt->format(n.getDouble(), s2); else s2 = fmt->format(n.getLong(), s2); if(DEBUG_VAR) logln(/*n.getString(temp) +*/ " F> " + escape(s2)); if(STRING_COMPARE) { if (s != s2) { errln("*** STRING ERROR \"" + escape(s) + "\" != \"" + escape(s2) + "\""); show = TRUE; } } if(EXACT_NUMERIC_COMPARE) { if(value != n) { errln("*** NUMERIC ERROR"); show = TRUE; } } else { // Compute proportional error double error = proportionalError(value, n); if(error > MAX_ERROR) { errln(UnicodeString("*** NUMERIC ERROR ") + error); show = TRUE; } if (error > max_numeric_error) max_numeric_error = error; if (error < min_numeric_error) min_numeric_error = error; } if (show) { errln(/*value.getString(temp) +*/ typeOf(value, temp) + " F> " + escape(s) + " P> " + (n.getType() == Formattable::kDouble ? n.getDouble() : (double)n.getLong()) /*n.getString(temp) */ + typeOf(n, temp) + " F> " + escape(s2)); } }
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 = NULL; #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 = (TimeUnit::UTimeUnitFields)(i+1)) { Hashtable* countToPatterns = fTimeUnitToCountToPatterns[i]; int32_t elemPos = UHASH_FIRST; const UHashElement* elem = NULL; while ((elem = countToPatterns->nextElement(elemPos)) != NULL){ const UHashTok keyTok = elem->key; UnicodeString* count = (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 = (MessageFormat**)valueTok.pointer; for (UTimeUnitFormatStyle style = UTMUTFMT_FULL_STYLE; style < UTMUTFMT_FORMAT_STYLE_COUNT; style = (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; getNumberFormat().parse(temp.getString(tmpString), tmpNumber, pStatus); if (U_FAILURE(pStatus)) { continue; } } else if (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); } else if (0 == countOfLongestMatch->compare(PLURAL_COUNT_ONE, 3)) { resultNumber = Formattable(1.0); } else if (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; TimeUnitAmount* tmutamt = new TimeUnitAmount(resultNumber, resultTimeUnit, status); if (U_SUCCESS(status)) { result.adoptObject(tmutamt); pos.setIndex(newPos); pos.setErrorIndex(-1); } else { pos.setIndex(oldPos); pos.setErrorIndex(0); } } }
void MessageFormatRegressionTest::Test4031438() { UErrorCode status = U_ZERO_ERROR; UnicodeString pattern1("Impossible {1} has occurred -- status code is {0} and message is {2}."); UnicodeString pattern2("Double '' Quotes {0} test and quoted '{1}' test plus 'other {2} stuff'."); MessageFormat *messageFormatter = new MessageFormat("", status); failure(status, "new MessageFormat"); const UBool possibleDataError = TRUE; //try { logln("Apply with pattern : " + pattern1); messageFormatter->applyPattern(pattern1, status); failure(status, "messageFormat->applyPattern"); //Object[] params = {new Integer(7)}; Formattable params []= { Formattable((int32_t)7) }; UnicodeString tempBuffer; FieldPosition pos(FieldPosition::DONT_CARE); tempBuffer = messageFormatter->format(params, 1, tempBuffer, pos, status); if(tempBuffer != "Impossible {1} has occurred -- status code is 7 and message is {2}." || failure(status, "MessageFormat::format")) dataerrln("Tests arguments < substitution failed"); logln("Formatted with 7 : " + tempBuffer); ParsePosition pp(0); int32_t count = 0; Formattable *objs = messageFormatter->parse(tempBuffer, pp, count); //if(objs[7/*params.length*/] != NULL) // errln("Parse failed with more than expected arguments"); NumberFormat *fmt = 0; UnicodeString temp, temp1; for (int i = 0; i < count; i++) { // convert to string if not already Formattable obj = objs[i]; temp.remove(); if(obj.getType() == Formattable::kString) temp = obj.getString(temp); else { fmt = NumberFormat::createInstance(status); switch (obj.getType()) { case Formattable::kLong: fmt->format(obj.getLong(), temp); break; case Formattable::kInt64: fmt->format(obj.getInt64(), temp); break; case Formattable::kDouble: fmt->format(obj.getDouble(), temp); break; default: break; } } // convert to string if not already Formattable obj1 = params[i]; temp1.remove(); if(obj1.getType() == Formattable::kString) temp1 = obj1.getString(temp1); else { fmt = NumberFormat::createInstance(status); switch (obj1.getType()) { case Formattable::kLong: fmt->format(obj1.getLong(), temp1); break; case Formattable::kInt64: fmt->format(obj1.getInt64(), temp1); break; case Formattable::kDouble: fmt->format(obj1.getDouble(), temp1); break; default: break; } } //if (objs[i] != NULL && objs[i].getString(temp1) != params[i].getString(temp2)) { if (temp != temp1) { errln("Parse failed on object " + objs[i].getString(temp1) + " at index : " + i); } } delete fmt; delete [] objs; // {sfb} does this apply? no way to really pass a null Formattable, // only a null array /*tempBuffer = messageFormatter->format(null, tempBuffer, FieldPosition(FieldPosition::DONT_CARE), status); if (tempBuffer != "Impossible {1} has occurred -- status code is {0} and message is {2}." || failure(status, "messageFormat->format")) errln("Tests with no arguments failed"); logln("Formatted with null : " + tempBuffer);*/ logln("Apply with pattern : " + pattern2); messageFormatter->applyPattern(pattern2, status); failure(status, "messageFormatter->applyPattern", possibleDataError); tempBuffer.remove(); tempBuffer = messageFormatter->format(params, 1, tempBuffer, pos, status); if (tempBuffer != "Double ' Quotes 7 test and quoted {1} test plus other {2} stuff.") dataerrln("quote format test (w/ params) failed. - %s", u_errorName(status)); logln("Formatted with params : " + tempBuffer); /*tempBuffer = messageFormatter->format(null); if (!tempBuffer.equals("Double ' Quotes {0} test and quoted {1} test plus other {2} stuff.")) errln("quote format test (w/ null) failed."); logln("Formatted with null : " + tempBuffer); logln("toPattern : " + messageFormatter.toPattern());*/ /*} catch (Exception foo) { errln("Exception when formatting in bug 4031438. "+foo.getMessage()); }*/ delete messageFormatter; }
static jobject parseRBNFImpl(JNIEnv *env, jclass clazz, jint addr, jstring text, jobject position, jboolean lenient) { // LOGI("ENTER parseRBNFImpl"); const char * parsePositionClassName = "java/text/ParsePosition"; const char * longClassName = "java/lang/Long"; const char * doubleClassName = "java/lang/Double"; UErrorCode status = U_ZERO_ERROR; UNumberFormat *fmt = (UNumberFormat *)(int)addr; jchar *str = (UChar *)env->GetStringChars(text, NULL); int strlength = env->GetStringLength(text); jclass parsePositionClass = env->FindClass(parsePositionClassName); jclass longClass = env->FindClass(longClassName); jclass doubleClass = env->FindClass(doubleClassName); jmethodID getIndexMethodID = env->GetMethodID(parsePositionClass, "getIndex", "()I"); jmethodID setIndexMethodID = env->GetMethodID(parsePositionClass, "setIndex", "(I)V"); jmethodID setErrorIndexMethodID = env->GetMethodID(parsePositionClass, "setErrorIndex", "(I)V"); jmethodID longInitMethodID = env->GetMethodID(longClass, "<init>", "(J)V"); jmethodID dblInitMethodID = env->GetMethodID(doubleClass, "<init>", "(D)V"); int parsePos = env->CallIntMethod(position, getIndexMethodID, NULL); // make sure the ParsePosition is valid. Actually icu4c would parse a number // correctly even if the parsePosition is set to -1, but since the RI fails // for that case we have to fail too if(parsePos < 0 || parsePos > strlength) { return NULL; } Formattable res; const UnicodeString src((UChar*)str, strlength, strlength); ParsePosition pp; pp.setIndex(parsePos); if(lenient) { unum_setAttribute(fmt, UNUM_LENIENT_PARSE, JNI_TRUE); } ((const NumberFormat*)fmt)->parse(src, res, pp); if(lenient) { unum_setAttribute(fmt, UNUM_LENIENT_PARSE, JNI_FALSE); } env->ReleaseStringChars(text, str); if(pp.getErrorIndex() == -1) { parsePos = pp.getIndex(); } else { env->CallVoidMethod(position, setErrorIndexMethodID, (jint) pp.getErrorIndex()); return NULL; } Formattable::Type numType; numType = res.getType(); UErrorCode fmtStatus; double resultDouble; long resultLong; int64_t resultInt64; switch(numType) { case Formattable::kDouble: resultDouble = res.getDouble(); env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos); return env->NewObject(doubleClass, dblInitMethodID, (jdouble) resultDouble); case Formattable::kLong: resultLong = res.getLong(); env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos); return env->NewObject(longClass, longInitMethodID, (jlong) resultLong); case Formattable::kInt64: resultInt64 = res.getInt64(); env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos); return env->NewObject(longClass, longInitMethodID, (jlong) resultInt64); default: break; } return NULL; }
void TimeUnitFormat::parseObject(const UnicodeString& source, Formattable& result, ParsePosition& pos) const { double resultNumber = -1; 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 = NULL; #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 = (TimeUnit::UTimeUnitFields)(i+1)) { Hashtable* countToPatterns = fTimeUnitToCountToPatterns[i]; int32_t elemPos = -1; const UHashElement* elem = NULL; while ((elem = countToPatterns->nextElement(elemPos)) != NULL){ const UHashTok keyTok = elem->key; UnicodeString* count = (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 = (MessageFormat**)valueTok.pointer; for (EStyle style = kFull; style < kTotal; style = (EStyle)(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 double tmpNumber = 0; if (pattern->getArgTypeCount() != 0) { // pattern with Number as beginning, such as "{0} d". // check to make sure that the timeUnit is consistent Formattable& temp = parsed[0]; if (temp.getType() == Formattable::kDouble) { tmpNumber = temp.getDouble(); } else if (temp.getType() == Formattable::kLong) { tmpNumber = temp.getLong(); } else { continue; } UnicodeString select = fPluralRules->select(tmpNumber); #ifdef TMUTFMT_DEBUG select.extract(0, select.length(), res, "UTF-8"); std::cout << "parse plural select count: " << res << "\n"; #endif if (*count != select) { 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 ( *countOfLongestMatch == PLURAL_COUNT_ZERO ) { resultNumber = 0; } else if ( *countOfLongestMatch == PLURAL_COUNT_ONE ) { resultNumber = 1; } else if ( *countOfLongestMatch == PLURAL_COUNT_TWO ) { resultNumber = 2; } else { // should not happen. // TODO: how to handle? resultNumber = 3; } } if (longestParseDistance == 0) { pos.setIndex(oldPos); pos.setErrorIndex(0); } else { UErrorCode status = U_ZERO_ERROR; TimeUnitAmount* tmutamt = new TimeUnitAmount(resultNumber, resultTimeUnit, status); if (U_SUCCESS(status)) { result.adoptObject(tmutamt); pos.setIndex(newPos); pos.setErrorIndex(-1); } else { pos.setIndex(oldPos); pos.setErrorIndex(0); } } }