public function parse(DateTimeParseContext $context, $parseText, $position) { $length = strlen($parseText); if ($position < 0 || $position > $length) { throw new \OutOfRangeException(); } $style = $context->isStrict() ? $this->textStyle : null; $chrono = $context->getEffectiveChronology(); $it = null; if ($chrono === null || $chrono == IsoChronology::INSTANCE()) { $it = $this->provider->getTextIterator($this->field, $style, $context->getLocale()); } else { $it = $this->provider->getTextIterator2($chrono, $this->field, $style, $context->getLocale()); } if ($it !== null) { foreach ($it as $key => $value) { // fix numeric indices $key = strval($key); if ($context->subSequenceEquals($key, 0, $parseText, $position, strlen($key))) { return $context->setParsedField($this->field, $value, $position, $position + strlen($key)); } } if ($context->isStrict()) { return ~$position; } } return $this->numberPrinterParser()->parse($context, $parseText, $position); }
public function parse(DateTimeParseContext $context, $text, $position) { // cache context before changed by decorated parser $strict = $context->isStrict(); // parse if ($position > strlen($text) || $position < 0) { throw new \OutOfRangeException(); } if ($position === strlen($text)) { return ~$position; // no more characters in the string } $endPos = $position + $this->padWidth; if ($endPos > strlen($text)) { if ($strict) { return ~$position; // not enough characters in the string to meet the parse width } $endPos = strlen($text); } $pos = $position; while ($pos < $endPos && $context->charEquals($text[$pos], $this->padChar)) { $pos++; } $text = substr($text, 0, $endPos); $resultPos = $this->printerParser->parse($context, $text, $pos); if ($resultPos !== $endPos && $strict) { return ~($position + $pos); // parse of decorated field didn't parse to the end } return $resultPos; }
public function parse(DateTimeParseContext $context, $text, $position) { $length = strlen($text); if ($position === $length) { return ~$position; } if ($position < 0 || $position >= $length) { throw new \OutOfRangeException(); } $sign = $text[$position]; $negative = false; $positive = false; if ($sign === $context->getDecimalStyle()->getPositiveSign()) { if ($this->signStyle->parse(true, $context->isStrict(), $this->minWidth === $this->maxWidth) === false) { return ~$position; } $positive = true; $position++; } else { if ($sign === $context->getDecimalStyle()->getNegativeSign()) { if ($this->signStyle->parse(false, $context->isStrict(), $this->minWidth === $this->maxWidth) === false) { return ~$position; } $negative = true; $position++; } else { if ($this->signStyle == SignStyle::ALWAYS() && $context->isStrict()) { return ~$position; } } } $effMinWidth = $context->isStrict() || $this->isFixedWidth($context) ? $this->minWidth : 1; $minEndPos = $position + $effMinWidth; if ($minEndPos > $length) { return ~$position; } $effMaxWidth = ($context->isStrict() || $this->isFixedWidth($context) ? $this->maxWidth : 9) + Math::max($this->subsequentWidth, 0); $total = 0; $totalBig = null; $pos = $position; for ($pass = 0; $pass < 2; $pass++) { $maxEndPos = Math::min($pos + $effMaxWidth, $length); while ($pos < $maxEndPos) { $ch = $text[$pos++]; $digit = $context->getDecimalStyle()->convertToDigit($ch); if ($digit < 0) { $pos--; if ($pos < $minEndPos) { return ~$position; // need at least min width digits } break; } if ($pos - $position > 18) { if ($totalBig === null) { $totalBig = \gmp_init($total); } $totalBig = \gmp_add(\gmp_mul($totalBig, "10"), \gmp_init($digit)); } else { $total = $total * 10 + $digit; } } if ($this->subsequentWidth > 0 && $pass === 0) { // re-parse now we know the correct width $parseLen = $pos - $position; $effMaxWidth = Math::max($effMinWidth, $parseLen - $this->subsequentWidth); $pos = $position; $total = 0; $totalBig = null; } else { break; } } if ($negative) { if ($totalBig !== null) { if (\gmp_cmp($totalBig, "0") === 0 && $context->isStrict()) { return ~($position - 1); // minus zero not allowed } $totalBig = \gmp_neg($totalBig); } else { if ($total === 0 && $context->isStrict()) { return ~($position - 1); // minus zero not allowed } $total = -$total; } } else { if ($this->signStyle == SignStyle::EXCEEDS_PAD() && $context->isStrict()) { $parseLen = $pos - $position; if ($positive) { if ($parseLen <= $this->minWidth) { return ~($position - 1); // '+' only parsed if minWidth exceeded } } else { if ($parseLen > $this->minWidth) { return ~$position; // '+' must be parsed if minWidth exceeded } } } } if ($totalBig !== null) { if (gmp_cmp($totalBig, "-9223372036854775808") < 0 || gmp_cmp($totalBig, "9223372036854775807") > 0) { // overflow, parse 1 less digit $totalBig = gmp_div($totalBig, "10"); $pos--; } return $this->setValue($context, gmp_intval($totalBig), $position, $pos); } return $this->setValue($context, $total, $position, $pos); }
public function parse(DateTimeParseContext $context, $text, $position) { $effectiveMin = $context->isStrict() ? $this->minWidth : 0; $effectiveMax = $context->isStrict() ? $this->maxWidth : 9; $length = strlen($text); if ($position === $length) { // valid if whole field is optional, invalid if minimum width return $effectiveMin > 0 ? ~$position : $position; } if ($this->decimalPoint) { if ($text[$position] != $context->getDecimalStyle()->getDecimalSeparator()) { // valid if whole field is optional, invalid if minimum width return $effectiveMin > 0 ? ~$position : $position; } $position++; } $minEndPos = $position + $effectiveMin; if ($minEndPos > $length) { return ~$position; // need at least min width digits } $maxEndPos = Math::min($position + $effectiveMax, $length); $total = 0; // can use int because we are only parsing up to 9 digits $pos = $position; while ($pos < $maxEndPos) { $ch = $text[$pos++]; $digit = $context->getDecimalStyle()->convertToDigit($ch); if ($digit < 0) { if ($pos < $minEndPos) { return ~$position; // need at least min width digits } $pos--; break; } $total = $total * 10 + $digit; } $div = 1 . str_repeat('0', 9 - ($pos - $position)); $fraction = gmp_mul($total, $div); $value = $this->convertFromFraction($fraction); return $context->setParsedField($this->field, $value, $position, $pos); }
/** * For a ReducedPrinterParser, fixed width is false if the mode is strict, * otherwise it is set as for NumberPrinterParser. * @param DateTimeParseContext $context the context * @return bool if the field is fixed width * @see DateTimeFormatterBuilder#appendValueReduced(java.time.temporal.TemporalField, int, int, int) */ public function isFixedWidth(DateTimeParseContext $context) { if ($context->isStrict() == false) { return false; } return parent::isFixedWidth($context); }