mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-08 06:53:45 +00:00
Use new unit identifier parsing code in number skeletons
This commit is contained in:
parent
96b1bacfb0
commit
ce3fa7af06
8 changed files with 57 additions and 64 deletions
|
@ -535,7 +535,7 @@ static const char * const gSubTypes[] = {
|
|||
"solar-mass",
|
||||
"stone",
|
||||
"ton",
|
||||
"base",
|
||||
"one",
|
||||
"percent",
|
||||
"permille",
|
||||
"gigawatt",
|
||||
|
@ -2030,6 +2030,8 @@ MeasureUnit::MeasureUnit(char* idToAdopt)
|
|||
if (fId == nullptr) {
|
||||
// Invalid; reset to the base dimensionless unit
|
||||
setTo(kBaseTypeIdx, kBaseSubTypeIdx);
|
||||
} else if (findBySubType(idToAdopt, this)) {
|
||||
// findBySubType frees fId
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2202,38 +2204,6 @@ bool MeasureUnit::findBySubType(StringPiece subType, MeasureUnit* output) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool MeasureUnit::parseCoreUnitIdentifier(
|
||||
StringPiece coreUnitIdentifier,
|
||||
MeasureUnit* numerator,
|
||||
MeasureUnit* denominator,
|
||||
UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// First search for the whole code unit identifier as a subType
|
||||
if (findBySubType(coreUnitIdentifier, numerator)) {
|
||||
return false; // found a numerator but not denominator
|
||||
}
|
||||
|
||||
// If not found, try breaking apart numerator and denominator
|
||||
int32_t perIdx = coreUnitIdentifier.find("-per-", 0);
|
||||
if (perIdx == -1) {
|
||||
// String does not contain "-per-"
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return false;
|
||||
}
|
||||
StringPiece numeratorStr(coreUnitIdentifier, 0, perIdx);
|
||||
StringPiece denominatorStr(coreUnitIdentifier, perIdx + 5);
|
||||
if (findBySubType(numeratorStr, numerator) && findBySubType(denominatorStr, denominator)) {
|
||||
return true; // found both a numerator and denominator
|
||||
}
|
||||
|
||||
// The numerator or denominator were invalid
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
MeasureUnit MeasureUnit::resolveUnitPerUnit(
|
||||
const MeasureUnit &unit, const MeasureUnit &perUnit, bool* isResolved) {
|
||||
int32_t unitOffset = unit.getOffset();
|
||||
|
|
|
@ -377,6 +377,9 @@ public:
|
|||
typedef MaybeStackVector<SingleUnit, 3> SingleUnitList;
|
||||
|
||||
void append(SingleUnit&& singleUnit, UErrorCode& status) {
|
||||
if (singleUnit.simpleUnitIndex == 0) {
|
||||
return;
|
||||
}
|
||||
if (singleUnit.power >= 0) {
|
||||
appendImpl(numerator, std::move(singleUnit), status);
|
||||
} else {
|
||||
|
@ -420,7 +423,7 @@ public:
|
|||
}
|
||||
|
||||
bool isSingle() const {
|
||||
return numerator.length() + denominator.length() == 1;
|
||||
return numerator.length() + denominator.length() <= 1;
|
||||
}
|
||||
|
||||
bool isEmpty() const {
|
||||
|
|
|
@ -11,7 +11,7 @@ U_NAMESPACE_BEGIN
|
|||
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NoUnit)
|
||||
|
||||
NoUnit U_EXPORT2 NoUnit::base() {
|
||||
return NoUnit("base");
|
||||
return NoUnit("one");
|
||||
}
|
||||
|
||||
NoUnit U_EXPORT2 NoUnit::percent() {
|
||||
|
|
|
@ -188,6 +188,12 @@ LongNameHandler*
|
|||
LongNameHandler::forMeasureUnit(const Locale &loc, const MeasureUnit &unitRef, const MeasureUnit &perUnit,
|
||||
const UNumberUnitWidth &width, const PluralRules *rules,
|
||||
const MicroPropsGenerator *parent, UErrorCode &status) {
|
||||
if (uprv_strlen(unitRef.getType()) == 0 || uprv_strlen(perUnit.getType()) == 0) {
|
||||
// TODO(ICU-20941): Unsanctioned unit. Not yet fully supported. Set an error code.
|
||||
status = U_UNSUPPORTED_ERROR;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MeasureUnit unit = unitRef;
|
||||
if (uprv_strcmp(perUnit.getType(), "none") != 0) {
|
||||
// Compound unit: first try to simplify (e.g., meters per second is its own unit).
|
||||
|
|
|
@ -1040,12 +1040,22 @@ void blueprint_helpers::parseIdentifierUnitOption(const StringSegment& segment,
|
|||
SKELETON_UCHAR_TO_CHAR(buffer, segment.toTempUnicodeString(), 0, segment.length(), status);
|
||||
|
||||
ErrorCode internalStatus;
|
||||
MeasureUnit::parseCoreUnitIdentifier(buffer.toStringPiece(), ¯os.unit, ¯os.perUnit, internalStatus);
|
||||
MeasureUnit fullUnit = MeasureUnit::forIdentifier(buffer.toStringPiece(), internalStatus);
|
||||
auto subUnits = fullUnit.getSingleUnits(internalStatus);
|
||||
if (internalStatus.isFailure()) {
|
||||
// throw new SkeletonSyntaxException("Invalid core unit identifier", segment, e);
|
||||
status = U_NUMBER_SKELETON_SYNTAX_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < subUnits.length(); i++) {
|
||||
const MeasureUnit& subUnit = subUnits[i];
|
||||
if (subUnit.getPower(status) > 0) {
|
||||
macros.unit = macros.unit.product(subUnit, status);
|
||||
} else {
|
||||
macros.perUnit = macros.perUnit.product(subUnit.reciprocal(status), status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void blueprint_helpers::parseFractionStem(const StringSegment& segment, MacroProps& macros,
|
||||
|
|
|
@ -553,26 +553,6 @@ class U_I18N_API MeasureUnit: public UObject {
|
|||
*/
|
||||
static int32_t internalGetIndexForTypeAndSubtype(const char *type, const char *subtype);
|
||||
|
||||
/**
|
||||
* ICU use only.
|
||||
* @return Whether subType is known to ICU.
|
||||
* @internal
|
||||
*/
|
||||
static bool findBySubType(StringPiece subType, MeasureUnit* output);
|
||||
|
||||
/**
|
||||
* ICU use only.
|
||||
* Parse a core unit identifier into a numerator and denominator unit.
|
||||
* @param coreUnitIdentifier The string to parse.
|
||||
* @param numerator Output: set to the numerator unit.
|
||||
* @param denominator Output: set to the denominator unit, if present.
|
||||
* @param status Set to U_ILLEGAL_ARGUMENT_ERROR if the core unit identifier is not known.
|
||||
* @return Whether both a numerator and denominator are returned.
|
||||
* @internal
|
||||
*/
|
||||
static bool parseCoreUnitIdentifier(
|
||||
StringPiece coreUnitIdentifier, MeasureUnit* numerator, MeasureUnit* denominator, UErrorCode& status);
|
||||
|
||||
/**
|
||||
* ICU use only.
|
||||
* @internal
|
||||
|
@ -3725,6 +3705,11 @@ private:
|
|||
void setTo(int32_t typeId, int32_t subTypeId);
|
||||
int32_t getOffset() const;
|
||||
static MeasureUnit *create(int typeId, int subTypeId, UErrorCode &status);
|
||||
|
||||
/**
|
||||
* @return Whether subType is known to ICU.
|
||||
*/
|
||||
static bool findBySubType(StringPiece subType, MeasureUnit* output);
|
||||
};
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
|
|
@ -3372,8 +3372,7 @@ void MeasureFormatTest::TestCompoundUnitOperations() {
|
|||
|
||||
assertTrue("order matters inequality", footInch != inchFoot);
|
||||
|
||||
// TODO(ICU-20920): Enable the one1 tests when the dimensionless base unit ID is updated
|
||||
// MeasureUnit one1;
|
||||
MeasureUnit one1;
|
||||
MeasureUnit one2 = MeasureUnit::forIdentifier("one", status);
|
||||
MeasureUnit one3 = MeasureUnit::forIdentifier("", status);
|
||||
MeasureUnit squareOne = one2.withPower(2, status);
|
||||
|
@ -3382,20 +3381,23 @@ void MeasureFormatTest::TestCompoundUnitOperations() {
|
|||
MeasureUnit onePerSquareKiloOne = squareKiloOne.reciprocal(status);
|
||||
MeasureUnit oneOne = MeasureUnit::forIdentifier("one-one", status);
|
||||
MeasureUnit onePlusOne = MeasureUnit::forIdentifier("one+one", status);
|
||||
MeasureUnit kilometer2 = one2.product(kilometer, status);
|
||||
|
||||
// verifySingleUnit(one1, UMEASURE_SI_PREFIX_ONE, 1, "one");
|
||||
verifySingleUnit(one1, UMEASURE_SI_PREFIX_ONE, 1, "one");
|
||||
verifySingleUnit(one2, UMEASURE_SI_PREFIX_ONE, 1, "one");
|
||||
verifySingleUnit(one3, UMEASURE_SI_PREFIX_ONE, 1, "one");
|
||||
verifySingleUnit(squareOne, UMEASURE_SI_PREFIX_ONE, 1, "one");
|
||||
verifySingleUnit(onePerOne, UMEASURE_SI_PREFIX_ONE, -1, "one-per-one");
|
||||
verifySingleUnit(onePerOne, UMEASURE_SI_PREFIX_ONE, 1, "one");
|
||||
verifySingleUnit(squareKiloOne, UMEASURE_SI_PREFIX_ONE, 1, "one");
|
||||
verifySingleUnit(onePerSquareKiloOne, UMEASURE_SI_PREFIX_ONE, -1, "one-per-one");
|
||||
verifySingleUnit(onePerSquareKiloOne, UMEASURE_SI_PREFIX_ONE, 1, "one");
|
||||
verifySingleUnit(oneOne, UMEASURE_SI_PREFIX_ONE, 1, "one");
|
||||
verifySingleUnit(onePlusOne, UMEASURE_SI_PREFIX_ONE, 1, "one");
|
||||
verifySingleUnit(kilometer2, UMEASURE_SI_PREFIX_KILO, 1, "kilometer");
|
||||
|
||||
// assertTrue("one equality", one1 == one2);
|
||||
assertTrue("one equality", one1 == one2);
|
||||
assertTrue("one equality", one2 == one3);
|
||||
assertTrue("one-per-one equality", onePerOne == onePerSquareKiloOne);
|
||||
assertTrue("kilometer equality", kilometer == kilometer2);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -674,7 +674,7 @@ void NumberFormatterApiTest::unitCompoundMeasure() {
|
|||
assertFormatDescending(
|
||||
u"Meters Per Second Short (unit that simplifies) and perUnit method",
|
||||
u"measure-unit/length-meter per-measure-unit/duration-second",
|
||||
u"~unit/meter-per-second", // does not round-trip to the full skeleton above
|
||||
u"unit/meter-per-second",
|
||||
NumberFormatter::with().unit(METER).perUnit(SECOND),
|
||||
Locale::getEnglish(),
|
||||
u"87,650 m/s",
|
||||
|
@ -718,6 +718,23 @@ void NumberFormatterApiTest::unitCompoundMeasure() {
|
|||
u"0.08765 J/fur",
|
||||
u"0.008765 J/fur",
|
||||
u"0 J/fur");
|
||||
|
||||
// TODO(ICU-20941): Support constructions such as this one.
|
||||
// assertFormatDescending(
|
||||
// u"Joules Per Furlong Short with unit identifier via API",
|
||||
// u"measure-unit/energy-joule per-measure-unit/length-furlong",
|
||||
// u"unit/joule-per-furlong",
|
||||
// NumberFormatter::with().unit(MeasureUnit::forIdentifier("joule-per-furlong", status)),
|
||||
// Locale::getEnglish(),
|
||||
// u"87,650 J/fur",
|
||||
// u"8,765 J/fur",
|
||||
// u"876.5 J/fur",
|
||||
// u"87.65 J/fur",
|
||||
// u"8.765 J/fur",
|
||||
// u"0.8765 J/fur",
|
||||
// u"0.08765 J/fur",
|
||||
// u"0.008765 J/fur",
|
||||
// u"0 J/fur");
|
||||
}
|
||||
|
||||
void NumberFormatterApiTest::unitCurrency() {
|
||||
|
@ -2777,7 +2794,7 @@ void NumberFormatterApiTest::fieldPositionCoverage() {
|
|||
FormattedNumber result = assertFormatSingle(
|
||||
message,
|
||||
u"measure-unit/length-meter per-measure-unit/duration-second unit-width-full-name",
|
||||
u"~unit/meter-per-second unit-width-full-name", // does not round-trip to the full skeleton above
|
||||
u"unit/meter-per-second unit-width-full-name",
|
||||
NumberFormatter::with().unit(METER).perUnit(SECOND).unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
|
||||
"ky", // locale with the interesting data
|
||||
68,
|
||||
|
|
Loading…
Add table
Reference in a new issue