/** * Creates a DecimalValue from a given string. * * The decimal notation for the value is based on ISO 31-0, with some modifications: * - the decimal separator is '.' (period). Comma is not used anywhere. * - leading and trailing as well as any internal whitespace is ignored * - the following characters are ignored: comma (","), apostrophe ("'"). * - scientific (exponential) notation is supported using the pattern /e[-+]\d+/ * - the number may start (or end) with a decimal point. * - leading zeroes are stripped, except directly before the decimal point * - trailing zeroes are stripped, except directly after the decimal point * - zero is always positive. * * @see StringValueParser::stringParse * * @since 0.1 * * @param string $value * * @return DecimalValue * @throws ParseException */ protected function stringParse($value) { $rawValue = $value; $value = $this->unlocalizer->unlocalizeNumber($value); //handle scientific notation list($value, $exponent) = $this->splitDecimalExponent($value); $value = $this->normalizeDecimal($value); if ($value === '') { throw new ParseException('Decimal value must not be empty', $rawValue, self::FORMAT_NAME); } try { $decimal = new DecimalValue($value); $decimal = $this->applyDecimalExponent($decimal, $exponent); return $decimal; } catch (IllegalValueException $ex) { throw new ParseException($ex->getMessage(), $rawValue, self::FORMAT_NAME); } }
/** * Splits a quantity string into its syntactic parts. * * @see newQuantityFromParts * * @param string $value * * @throws InvalidArgumentException If $value is not a string * @throws ParseException If $value does not match the expected pattern * @return array list( $amount, $exactness, $margin, $unit ). * Parts not present in $value will be null */ private function splitQuantityString($value) { if (!is_string($value)) { throw new InvalidArgumentException('$value must be a string'); } //TODO: allow explicitly specifying the number of significant figures //TODO: allow explicitly specifying the uncertainty interval $numberPattern = $this->unlocalizer->getNumberRegex('@'); $unitPattern = $this->unlocalizer->getUnitRegex('@'); $pattern = '@^' . '\\s*(' . $numberPattern . ')' . '\\s*(?:' . '([~!])' . '|(?:\\+/?-|±)\\s*(' . $numberPattern . ')' . '|' . ')' . '\\s*(' . $unitPattern . ')?' . '\\s*$@u'; if (!preg_match($pattern, $value, $groups)) { throw new ParseException('Malformed quantity', $value, self::FORMAT_NAME); } // Remove $0. array_shift($groups); array_walk($groups, function (&$element) { if ($element === '') { $element = null; } }); return array_pad($groups, 4, null); }
/** * Splits a quantity string into its syntactic parts. * * @see newQuantityFromParts * * @param string $value * * @throws InvalidArgumentException If $value is not a string * @throws ParseException If $value does not match the expected pattern * @return array list( $amount, $exactness, $margin, $unit ). * Parts not present in $value will be null */ private function splitQuantityString($value) { if (!is_string($value)) { throw new InvalidArgumentException('$value must be a string'); } //TODO: allow explicitly specifying the number of significant figures //TODO: allow explicitly specifying the uncertainty interval $numberPattern = $this->unlocalizer->getNumberRegex('@'); $unitPattern = $this->unlocalizer->getUnitRegex('@'); $pattern = '@^' . '\\s*(' . $numberPattern . ')' . '\\s*(?:' . '([~!])' . '|(?:\\+/?-|±)\\s*(' . $numberPattern . ')' . '|' . ')' . '\\s*(' . $unitPattern . ')?' . '\\s*$@u'; if (!preg_match($pattern, $value, $groups)) { throw new ParseException('Malformed quantity', $value, self::FORMAT_NAME); } for ($i = 1; $i <= 4; $i++) { if (!isset($groups[$i])) { $groups[$i] = null; } elseif ($groups[$i] === '') { $groups[$i] = null; } } array_shift($groups); // remove $groups[0] return $groups; }