std::pair<std::string,std::string> decomposeScaledUnitString(const std::string& s) { if (!isScaledUnit(s)) { LOG_FREE_AND_THROW("openstudio.QuantityRegex","Cannot decompose " << s << " into a scale and a compound unit because it is not a scaled unit."); } std::pair<std::string,std::string> result; boost::match_results<std::string::const_iterator> match; boost::regex scaleRegex("(\\\\?[\\l\\u]{1,5})\\("); // pull out scale if (!boost::regex_search(s,match,scaleRegex,boost::match_continuous)) { LOG_FREE_AND_THROW("openstudio.QuantityRegex","Could not extract a scale from the scaled unit " << s << "."); } result.first = std::string(match[1].first,match[1].second); // pull out compound unit if (!boost::regex_search(s,match,regexEmbeddedCompoundUnit())) { LOG_FREE_AND_THROW("openstudio.QuantityRegex","Could not extract a compound unit from " << s << "."); } int i = 1; while (!match[i].matched) {++i;} result.second = std::string(match[1].first,match[1].second); return result; }
boost::optional<Unit> UnitFactorySingleton::createUnit(const std::string& unitString, UnitSystem system) const { if (m_callbackMaps.size() == 0) { LOG(Warn,"UnitFactorySingleton::createUnit called, but the maps appear to be empty."); } if (!unitString.empty() && !isUnit(unitString)) { LOG(Error,unitString << " is not properly formatted."); return boost::none; } OptionalUnit result = createUnitSimple(unitString,system); if (result) { return *result; } // no luck--start parsing std::string wUnitString(unitString); ScaleConstant scale = ScaleFactory::instance().createScale(0); if (isScaledUnit(wUnitString)) { std::pair<std::string,std::string> scaleAndUnit = decomposeScaledUnitString(wUnitString); scale = ScaleFactory::instance().createScale(scaleAndUnit.first); if (scale().value == 0.0) { LOG(Error,"Scaled unit string " << wUnitString << " uses invalid scale abbreviation " << scaleAndUnit.first << "."); return boost::none; } wUnitString = scaleAndUnit.second; } // wUnitString should now be compound unit std::pair< std::vector<std::string>,std::vector<std::string> > atomicUnits = decomposeCompoundUnitString(wUnitString); // loop through numerator std::vector<std::string>::const_iterator atomicUnitIter; std::vector<std::string>::const_iterator vectorEnd = atomicUnits.first.end(); std::pair<std::string,int> atomicUnit; for (atomicUnitIter = atomicUnits.first.begin(); atomicUnitIter != vectorEnd; ++atomicUnitIter) { // decompose into baseUnit and exponent atomicUnit = decomposeAtomicUnitString(*atomicUnitIter); // look for baseUnit OptionalUnit baseUnit = createUnitSimple(atomicUnit.first,system); if (!baseUnit) { // decompose into scale, baseUnit std::pair<std::string,std::string> scaleAndBaseUnit = extractScaleAbbreviation(atomicUnit.first); if (!scaleAndBaseUnit.first.empty()) { baseUnit = createUnitSimple(scaleAndBaseUnit.second,system); if (!baseUnit) { baseUnit = Unit(); baseUnit->setBaseUnitExponent(scaleAndBaseUnit.second,1); } baseUnit->setScale(scaleAndBaseUnit.first); } else { baseUnit = Unit(); baseUnit->setBaseUnitExponent(atomicUnit.first,1); } } baseUnit->pow(atomicUnit.second); if (!result) { result = baseUnit; } else { result = (*result) * (*baseUnit); } } // loop through denominator vectorEnd = atomicUnits.second.end(); for (atomicUnitIter = atomicUnits.second.begin(); atomicUnitIter != vectorEnd; ++atomicUnitIter) { // decompose into baseUnit and exponent atomicUnit = decomposeAtomicUnitString(*atomicUnitIter); // look for baseUnit OptionalUnit baseUnit = createUnitSimple(atomicUnit.first,system); if (!baseUnit) { // decompose into scale, baseUnit std::pair<std::string,std::string> scaleAndBaseUnit = extractScaleAbbreviation(atomicUnit.first); if (!scaleAndBaseUnit.first.empty()) { baseUnit = createUnitSimple(scaleAndBaseUnit.second,system); if (!baseUnit) { LOG(Info,scaleAndBaseUnit.second << " is not a registered baseUnit (in the selected system). " << "Returning it as-is in a mixed Unit (not SI, IP, etc.)."); baseUnit = Unit(); baseUnit->setBaseUnitExponent(scaleAndBaseUnit.second,1); } baseUnit->setScale(scaleAndBaseUnit.first); } else { LOG(Info,scaleAndBaseUnit.second << " is not a registered baseUnit (in the selected system). " << "Returning it as-is in a mixed Unit (not SI, IP, etc.)."); baseUnit = Unit(); baseUnit->setBaseUnitExponent(atomicUnit.first,1); } } baseUnit->pow(atomicUnit.second); if (!result) { baseUnit->pow(-1); result = baseUnit; } else { result = (*result) / (*baseUnit); } } BOOST_ASSERT(result); // impose overall scale if (scale().exponent != 0) { ScaleOpReturnType resultScale = scale()*result->scale(); result->setScale(resultScale.first().exponent); } return result; }