void capi() { UNumberFormat *fmt; UErrorCode status = U_ZERO_ERROR; /* The string "987654321.123" as UChars */ UChar str[] = { 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2E, 0x31, 0x32, 0x33, 0 }; UChar buf[256]; int32_t needed; double a; /* Create a formatter for the US locale */ fmt = unum_open( UNUM_DECIMAL, /* style */ 0, /* pattern */ 0, /* patternLength */ "en_US", /* locale */ 0, /* parseErr */ &status); if (U_FAILURE(status)) { printf("FAIL: unum_open\n"); exit(1); } /* Use the formatter to parse a number. When using the C API, we have to specify whether we want a double or a long in advance. We pass in NULL for the position pointer in order to get the default behavior which is to parse from the start. */ a = unum_parseDouble(fmt, str, u_strlen(str), NULL, &status); if (U_FAILURE(status)) { printf("FAIL: unum_parseDouble\n"); exit(1); } /* Show the result */ printf("unum_parseDouble(\""); uprintf(str); printf("\") => %g\n", a); /* Use the formatter to format the same number back into a string in the US locale. The return value is the buffer size needed. We're pretty sure we have enough space, but in a production application one would check this value. We pass in NULL for the UFieldPosition pointer because we don't care to receive that data. */ needed = unum_formatDouble(fmt, a, buf, 256, NULL, &status); if (U_FAILURE(status)) { printf("FAIL: format_parseDouble\n"); exit(1); } /* Show the result */ printf("unum_formatDouble(%g) => \"", a); uprintf(buf); printf("\"\n"); /* Release the storage used by the formatter */ unum_close(fmt); }
static Variant HHVM_METHOD(NumberFormatter, parse, const String& value, int64_t type, VRefParam position) { NUMFMT_GET(obj, this_, false); UErrorCode error = U_ZERO_ERROR; icu::UnicodeString val(u16(value, error)); NUMFMT_CHECK(obj, error, false); Variant ret; int32_t pos = position.toInt64(); error = U_ZERO_ERROR; switch (type) { case UNUM(TYPE_INT32): ret = unum_parse(obj->formatter(), val.getBuffer(), val.length(), &pos, &error); break; case UNUM(TYPE_INT64): ret = unum_parseInt64(obj->formatter(), val.getBuffer(), val.length(), &pos, &error); break; case UNUM(TYPE_DOUBLE): ret = unum_parseDouble(obj->formatter(), val.getBuffer(), val.length(), &pos, &error); break; default: obj->setError(U_UNSUPPORTED_ERROR); return false; } NUMFMT_CHECK(obj, error, false); position = pos; return ret; }
static int32_t u_scanf_spellout_handler(UFILE *input, u_scanf_spec_info *info, ufmt_args *args, const UChar *fmt, int32_t *fmtConsumed, int32_t *argConverted) { int32_t len; double num; UNumberFormat *format; int32_t parsePos = 0; int32_t skipped; UErrorCode status = U_ZERO_ERROR; /* skip all ws in the input */ skipped = u_scanf_skip_leading_ws(input, info->fPadChar); /* fill the input's internal buffer */ ufile_fill_uchar_buffer(input); /* determine the size of the input's buffer */ len = (int32_t)(input->str.fLimit - input->str.fPos); /* truncate to the width, if specified */ if(info->fWidth != -1) len = ufmt_min(len, info->fWidth); /* get the formatter */ format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_SPELLOUT); /* handle error */ if(format == 0) return 0; /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */ /* This is not applicable to RBNF. */ /*skipped += u_scanf_skip_leading_positive_sign(input, format, &status);*/ /* parse the number */ num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status); if (!info->fSkipArg) { *(double*)(args[0].ptrValue) = num; } /* mask off any necessary bits */ /* if(! info->fIsLong_double) num &= DBL_MAX;*/ /* update the input's position to reflect consumed data */ input->str.fPos += parsePos; /* we converted 1 arg */ *argConverted = !info->fSkipArg; return parsePos + skipped; }
JSValue IntlPluralRules::select(ExecState& exec, double value) { VM& vm = exec.vm(); auto scope = DECLARE_THROW_SCOPE(vm); // 13.1.4 ResolvePlural (pluralRules, n) // https://tc39.github.io/ecma402/#sec-resolveplural if (!m_initializedPluralRules) return throwTypeError(&exec, scope, "Intl.PluralRules.prototype.select called on value that's not an object initialized as a PluralRules"_s); if (!std::isfinite(value)) return jsNontrivialString(&exec, "other"_s); #if HAVE(ICU_PLURALRULES_WITH_FORMAT) UErrorCode status = U_ZERO_ERROR; Vector<UChar, 8> result(8); auto length = uplrules_selectWithFormat(m_pluralRules.get(), value, m_numberFormat.get(), result.data(), result.size(), &status); if (U_FAILURE(status)) return throwTypeError(&exec, scope, "failed to select plural value"_s); #else UErrorCode status = U_ZERO_ERROR; Vector<UChar, 32> buffer(32); auto length = unum_formatDouble(m_numberFormat.get(), value, buffer.data(), buffer.size(), nullptr, &status); if (status == U_BUFFER_OVERFLOW_ERROR) { buffer.grow(length); status = U_ZERO_ERROR; unum_formatDouble(m_numberFormat.get(), value, buffer.data(), length, nullptr, &status); } if (U_FAILURE(status)) return throwTypeError(&exec, scope, "failed to select plural value"_s); double formatted = unum_parseDouble(m_numberFormat.get(), buffer.data(), length, nullptr, &status); if (U_FAILURE(status)) return throwTypeError(&exec, scope, "failed to select plural value"_s); // Can only be 'zero', 'one', 'two', 'few', 'many' or 'other' status = U_ZERO_ERROR; Vector<UChar, 8> result(8); length = uplrules_select(m_pluralRules.get(), formatted, result.data(), result.size(), &status); if (U_FAILURE(status)) return throwTypeError(&exec, scope, "failed to select plural value"_s); #endif return jsString(&exec, String(result.data(), length)); }
/* Test exponential pattern*/ static void TestExponential(void) { int32_t pat_length, val_length, lval_length; int32_t ival, ilval, p, v, lneed; UNumberFormat *fmt; int32_t ppos; UChar *upat; UChar pattern[20]; UChar *str=NULL; UChar uvalfor[20], ulvalfor[20]; char tempMsgBug[256]; double a; UErrorCode status = U_ZERO_ERROR; #if U_PLATFORM == U_PF_OS390 static const double val[] = { 0.01234, 123456789, 1.23e75, -3.141592653e-78 }; #else static const double val[] = { 0.01234, 123456789, 1.23e300, -3.141592653e-271 }; #endif static const char* pat[] = { "0.####E0", "00.000E00", "##0.######E000", "0.###E0;[0.###E0]" }; static const int32_t lval[] = { 0, -1, 1, 123456789 }; static const char* valFormat[] = { "1.234E-2", "1.2346E8", "1.23E300", "-3.1416E-271", "12.340E-03", "12.346E07", "12.300E299", "-31.416E-272", "12.34E-003", "123.4568E006", "1.23E300", "-314.1593E-273", "1.234E-2", "1.235E8", "1.23E300", "[3.142E-271]" }; static const char* lvalFormat[] = { "0E0", "-1E0", "1E0", "1.2346E8", "00.000E00", "-10.000E-01", "10.000E-01", "12.346E07", "0E000", "-1E000", "1E000", "123.4568E006", "0E0", "[1E0]", "1E0", "1.235E8" }; static const double valParse[] = { #if U_PLATFORM == U_PF_OS390 0.01234, 123460000, 1.23E75, -3.1416E-78, 0.01234, 123460000, 1.23E75, -3.1416E-78, 0.01234, 123456800, 1.23E75, -3.141593E-78, 0.01234, 123500000, 1.23E75, -3.142E-78 #else /* We define the whole IEEE 754 number in the 4th column because Visual Age 7 has a bug in rounding numbers. */ 0.01234, 123460000, 1.23E300, -3.1415999999999999E-271, 0.01234, 123460000, 1.23E300, -3.1415999999999999E-271, 0.01234, 123456800, 1.23E300, -3.1415929999999999E-271, 0.01234, 123500000, 1.23E300, -3.1420000000000001E-271 #endif }; static const int32_t lvalParse[] = { 0, -1, 1, 123460000, 0, -1, 1, 123460000, 0, -1, 1, 123456800, 0, -1, 1, 123500000 }; pat_length = UPRV_LENGTHOF(pat); val_length = UPRV_LENGTHOF(val); lval_length = UPRV_LENGTHOF(lval); ival = 0; ilval = 0; for (p=0; p < pat_length; ++p) { upat=(UChar*)malloc(sizeof(UChar) * (strlen(pat[p])+1) ); u_uastrcpy(upat, pat[p]); fmt=unum_open(UNUM_IGNORE,upat, u_strlen(upat), "en_US",NULL, &status); if (U_FAILURE(status)) { log_err_status(status, "FAIL: Bad status returned by Number format construction with pattern %s -> %s\n", pat[p], u_errorName(status)); continue; } lneed= u_strlen(upat) + 1; unum_toPattern(fmt, FALSE, pattern, lneed, &status); log_verbose("Pattern \" %s \" -toPattern-> \" %s \" \n", upat, u_austrcpy(tempMsgBug, pattern) ); for (v=0; v<val_length; ++v) { /*format*/ lneed=0; lneed=unum_formatDouble(fmt, val[v], NULL, lneed, NULL, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; str=(UChar*)malloc(sizeof(UChar) * (lneed+1) ); unum_formatDouble(fmt, val[v], str, lneed+1, NULL, &status); } if(U_FAILURE(status)) { log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status) ); } u_uastrcpy(uvalfor, valFormat[v+ival]); if(u_strcmp(str, uvalfor) != 0) log_verbose("FAIL: Expected %s ( %s )\n", valFormat[v+ival], u_austrcpy(tempMsgBug, uvalfor) ); /*parsing*/ ppos=0; a=unum_parseDouble(fmt, str, u_strlen(str), &ppos, &status); if (ppos== u_strlen(str)) { if (a != valParse[v+ival]) log_err("FAIL: Expected: %e, Got: %g\n", valParse[v+ival], a); } else log_err(" FAIL: Partial parse ( %d chars ) -> %e\n", ppos, a); free(str); } for (v=0; v<lval_length; ++v) { /*format*/ lneed=0; lneed=unum_formatDouble(fmt, lval[v], NULL, lneed, NULL, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; str=(UChar*)malloc(sizeof(UChar) * (lneed+1) ); unum_formatDouble(fmt, lval[v], str, lneed+1, NULL, &status); } if(U_FAILURE(status)) { log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status) ); } /*printf(" Format %e -> %s\n", lval[v], austrdup(str) );*/ u_uastrcpy(ulvalfor, lvalFormat[v+ilval]); if(u_strcmp(str, ulvalfor) != 0) log_err("FAIL: Expected %s ( %s )\n", valFormat[v+ilval], austrdup(ulvalfor) ); /*parsing*/ ppos=0; a=unum_parseDouble(fmt, str, u_strlen(str), &ppos, &status); if (ppos== u_strlen(str)) { /*printf(" Parse -> %e\n", a);*/ if (a != lvalParse[v+ilval]) log_err("FAIL: Expected : %e\n", valParse[v+ival]); } else log_err(" FAIL: Partial parse ( %d chars ) -> %e\n", ppos, a); free(str); } ival += val_length; ilval += lval_length; unum_close(fmt); free(upat); } }
static int32_t u_scanf_scidbl_handler(UFILE *input, u_scanf_spec_info *info, ufmt_args *args, const UChar *fmt, int32_t *fmtConsumed, int32_t *argConverted) { int32_t len; double num; UNumberFormat *scientificFormat, *genericFormat; /*int32_t scientificResult, genericResult;*/ double scientificResult, genericResult; int32_t scientificParsePos = 0, genericParsePos = 0, parsePos = 0; int32_t skipped; UErrorCode scientificStatus = U_ZERO_ERROR; UErrorCode genericStatus = U_ZERO_ERROR; /* since we can't determine by scanning the characters whether */ /* a number was formatted in the 'f' or 'g' styles, parse the */ /* string with both formatters, and assume whichever one */ /* parsed the most is the correct formatter to use */ /* skip all ws in the input */ skipped = u_scanf_skip_leading_ws(input, info->fPadChar); /* fill the input's internal buffer */ ufile_fill_uchar_buffer(input); /* determine the size of the input's buffer */ len = (int32_t)(input->str.fLimit - input->str.fPos); /* truncate to the width, if specified */ if(info->fWidth != -1) len = ufmt_min(len, info->fWidth); /* get the formatters */ scientificFormat = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_SCIENTIFIC); genericFormat = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_DECIMAL); /* handle error */ if(scientificFormat == 0 || genericFormat == 0) return 0; /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */ skipped += u_scanf_skip_leading_positive_sign(input, genericFormat, &genericStatus); /* parse the number using each format*/ scientificResult = unum_parseDouble(scientificFormat, input->str.fPos, len, &scientificParsePos, &scientificStatus); genericResult = unum_parseDouble(genericFormat, input->str.fPos, len, &genericParsePos, &genericStatus); /* determine which parse made it farther */ if(scientificParsePos > genericParsePos) { /* stash the result in num */ num = scientificResult; /* update the input's position to reflect consumed data */ parsePos += scientificParsePos; } else { /* stash the result in num */ num = genericResult; /* update the input's position to reflect consumed data */ parsePos += genericParsePos; } input->str.fPos += parsePos; if (!info->fSkipArg) { if (info->fIsLong) *(double*)(args[0].ptrValue) = num; else if (info->fIsLongDouble) *(long double*)(args[0].ptrValue) = num; else *(float*)(args[0].ptrValue) = (float)num; } /* mask off any necessary bits */ /* if(! info->fIsLong_double) num &= DBL_MAX;*/ /* we converted 1 arg */ *argConverted = !info->fSkipArg; return parsePos + skipped; }
static int32_t u_scanf_scientific_handler(UFILE *input, u_scanf_spec_info *info, ufmt_args *args, const UChar *fmt, int32_t *fmtConsumed, int32_t *argConverted) { int32_t len; double num; UNumberFormat *format; int32_t parsePos = 0; int32_t skipped; UErrorCode status = U_ZERO_ERROR; UChar srcExpBuf[UPRINTF_SYMBOL_BUFFER_SIZE]; int32_t srcLen, expLen; UChar expBuf[UPRINTF_SYMBOL_BUFFER_SIZE]; /* skip all ws in the input */ skipped = u_scanf_skip_leading_ws(input, info->fPadChar); /* fill the input's internal buffer */ ufile_fill_uchar_buffer(input); /* determine the size of the input's buffer */ len = (int32_t)(input->str.fLimit - input->str.fPos); /* truncate to the width, if specified */ if(info->fWidth != -1) len = ufmt_min(len, info->fWidth); /* get the formatter */ format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_SCIENTIFIC); /* handle error */ if(format == 0) return 0; /* set the appropriate flags on the formatter */ srcLen = unum_getSymbol(format, UNUM_EXPONENTIAL_SYMBOL, srcExpBuf, sizeof(srcExpBuf), &status); /* Upper/lower case the e */ if (info->fSpec == (UChar)0x65 /* e */) { expLen = u_strToLower(expBuf, (int32_t)sizeof(expBuf), srcExpBuf, srcLen, input->str.fBundle.fLocale, &status); } else { expLen = u_strToUpper(expBuf, (int32_t)sizeof(expBuf), srcExpBuf, srcLen, input->str.fBundle.fLocale, &status); } unum_setSymbol(format, UNUM_EXPONENTIAL_SYMBOL, expBuf, expLen, &status); /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */ skipped += u_scanf_skip_leading_positive_sign(input, format, &status); /* parse the number */ num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status); if (!info->fSkipArg) { if (info->fIsLong) *(double*)(args[0].ptrValue) = num; else if (info->fIsLongDouble) *(long double*)(args[0].ptrValue) = num; else *(float*)(args[0].ptrValue) = (float)num; } /* mask off any necessary bits */ /* if(! info->fIsLong_double) num &= DBL_MAX;*/ /* update the input's position to reflect consumed data */ input->str.fPos += parsePos; /* we converted 1 arg */ *argConverted = !info->fSkipArg; return parsePos + skipped; }