Пример #1
0
 /**
  * Parses date and / or time in strict mode.
  *
  * @param string $datetimeToParse Date/time to be parsed
  * @param array $parsedFormat Format parsed by DatesReader
  * @param array $localizedLiterals Array of date / time literals from CLDR
  * @return array Array of parsed date and / or time elements, FALSE on failure
  * @throws \TYPO3\FLOW3\I18n\Exception\InvalidArgumentException When unexpected symbol found in format
  * @see \TYPO3\FLOW3\I18n\Cldr\Reader\DatesReader
  */
 protected function doParsingInStrictMode($datetimeToParse, array $parsedFormat, array $localizedLiterals)
 {
     $datetimeElements = array('year' => NULL, 'month' => NULL, 'day' => NULL, 'hour' => NULL, 'minute' => NULL, 'second' => NULL, 'timezone' => NULL);
     $using12HourClock = FALSE;
     $timeIsPm = FALSE;
     try {
         foreach ($parsedFormat as $subformat) {
             if (is_array($subformat)) {
                 // This is literal string, should match exactly
                 if (\TYPO3\FLOW3\I18n\Utility::stringBeginsWith($datetimeToParse, $subformat[0])) {
                     $datetimeToParse = substr_replace($datetimeToParse, '', 0, strlen($subformat[0]));
                     continue;
                 } else {
                     return FALSE;
                 }
             }
             $lengthOfSubformat = strlen($subformat);
             $numberOfCharactersToRemove = 0;
             switch ($subformat[0]) {
                 case 'h':
                 case 'K':
                     $hour = $this->extractAndCheckNumber($datetimeToParse, $lengthOfSubformat === 2, 1, 12);
                     $numberOfCharactersToRemove = $lengthOfSubformat === 1 && $hour < 10 ? 1 : 2;
                     if ($subformat[0] === 'h' && $hour === 12) {
                         $hour = 0;
                     }
                     $datetimeElements['hour'] = $hour;
                     $using12HourClock = TRUE;
                     break;
                 case 'k':
                 case 'H':
                     $hour = $this->extractAndCheckNumber($datetimeToParse, $lengthOfSubformat === 2, 1, 24);
                     $numberOfCharactersToRemove = $lengthOfSubformat === 1 && $hour < 10 ? 1 : 2;
                     if ($subformat[0] === 'k' && $hour === 24) {
                         $hour = 0;
                     }
                     $datetimeElements['hour'] = $hour;
                     break;
                 case 'a':
                     $dayPeriods = $localizedLiterals['dayPeriods']['format']['wide'];
                     if (\TYPO3\FLOW3\I18n\Utility::stringBeginsWith($datetimeToParse, $dayPeriods['am'])) {
                         $numberOfCharactersToRemove = strlen($dayPeriods['am']);
                     } elseif (\TYPO3\FLOW3\I18n\Utility::stringBeginsWith($datetimeToParse, $dayPeriods['pm'])) {
                         $timeIsPm = TRUE;
                         $numberOfCharactersToRemove = strlen($dayPeriods['pm']);
                     } else {
                         return FALSE;
                     }
                     break;
                 case 'm':
                     $minute = $this->extractAndCheckNumber($datetimeToParse, $lengthOfSubformat === 2, 0, 59);
                     $numberOfCharactersToRemove = $lengthOfSubformat === 1 && $minute < 10 ? 1 : 2;
                     $datetimeElements['minute'] = $minute;
                     break;
                 case 's':
                     $second = $this->extractAndCheckNumber($datetimeToParse, $lengthOfSubformat === 2, 0, 59);
                     $numberOfCharactersToRemove = $lengthOfSubformat === 1 && $second < 10 ? 1 : 2;
                     $datetimeElements['second'] = $second;
                     break;
                 case 'd':
                     $dayOfTheMonth = $this->extractAndCheckNumber($datetimeToParse, $lengthOfSubformat === 2, 1, 31);
                     $numberOfCharactersToRemove = $lengthOfSubformat === 1 && $dayOfTheMonth < 10 ? 1 : 2;
                     $datetimeElements['day'] = $dayOfTheMonth;
                     break;
                 case 'M':
                 case 'L':
                     $typeOfLiteral = $subformat[0] === 'L' ? 'stand-alone' : 'format';
                     if ($lengthOfSubformat <= 2) {
                         $month = $this->extractAndCheckNumber($datetimeToParse, $lengthOfSubformat === 2, 1, 12);
                         $numberOfCharactersToRemove = $lengthOfSubformat === 1 && $month < 10 ? 1 : 2;
                     } else {
                         if ($lengthOfSubformat <= 4) {
                             $lengthOfLiteral = $lengthOfSubformat === 3 ? 'abbreviated' : 'wide';
                             $month = 0;
                             foreach ($localizedLiterals['months'][$typeOfLiteral][$lengthOfLiteral] as $monthId => $monthName) {
                                 if (\TYPO3\FLOW3\I18n\Utility::stringBeginsWith($datetimeToParse, $monthName)) {
                                     $month = $monthId;
                                     break;
                                 }
                             }
                         } else {
                             throw new \TYPO3\FLOW3\I18n\Exception\InvalidArgumentException('Cannot parse formats with narrow month pattern as it is not unique.', 1279965245);
                         }
                     }
                     if ($month === 0) {
                         return FALSE;
                     }
                     $datetimeElements['month'] = $month;
                     break;
                 case 'y':
                     if ($lengthOfSubformat === 2) {
                         /** @todo How should the XX date be returned? Like 19XX? **/
                         $year = substr($datetimeToParse, 0, 2);
                         $numberOfCharactersToRemove = 2;
                     } else {
                         $year = substr($datetimeToParse, 0, $lengthOfSubformat);
                         for ($i = $lengthOfSubformat; $i < strlen($datetimeToParse); ++$i) {
                             if (is_numeric($datetimeToParse[$i])) {
                                 $year .= $datetimeToParse[$i];
                             } else {
                                 break;
                             }
                         }
                         $numberOfCharactersToRemove = $i;
                     }
                     if (!is_numeric($year)) {
                         return FALSE;
                     }
                     $year = (int) $year;
                     $datetimeElements['year'] = $year;
                     break;
                 case 'v':
                 case 'z':
                     if ($lengthOfSubformat <= 3) {
                         $pattern = self::PATTERN_MATCH_STRICT_TIMEZONE_ABBREVIATION;
                     } else {
                         $pattern = self::PATTERN_MATCH_STRICT_TIMEZONE_TZ;
                     }
                     if (preg_match($pattern, $datetimeToParse, $matches) !== 1) {
                         return FALSE;
                     }
                     $datetimeElements['timezone'] = $matches[0];
                     break;
                 case 'D':
                 case 'F':
                 case 'w':
                 case 'W':
                 case 'Q':
                 case 'q':
                 case 'G':
                 case 'S':
                 case 'E':
                 case 'Y':
                 case 'u':
                 case 'l':
                 case 'g':
                 case 'e':
                 case 'c':
                 case 'A':
                 case 'Z':
                 case 'V':
                     // Silently ignore unsupported formats or formats that there is no need to parse
                     break;
                 default:
                     throw new \TYPO3\FLOW3\I18n\Exception\InvalidArgumentException('Unexpected format symbol, "' . $subformat[0] . '" detected for date / time parsing.', 1279965528);
             }
             if ($using12HourClock && $timeIsPm) {
                 $datetimeElements['hour'] += 12;
                 $timeIsPm = FALSE;
             }
             if ($numberOfCharactersToRemove > 0) {
                 $datetimeToParse = substr_replace($datetimeToParse, '', 0, $numberOfCharactersToRemove);
             }
         }
     } catch (\TYPO3\FLOW3\I18n\Parser\Exception\InvalidParseStringException $exception) {
         // Method extractAndCheckNumber() throws exception when constraints in $datetimeToParse are not fulfilled
         return FALSE;
     }
     return $datetimeElements;
 }
Пример #2
0
 /**
  * Parses number in lenient mode.
  *
  * Lenient parsing ignores everything that can be ignored, and tries to
  * extract number from the string, even if it's not well formed.
  *
  * Implementation is simple but should work more often than strict parsing.
  *
  * Algorithm:
  * 1. Find first digit
  * 2. Find last digit
  * 3. Find decimal separator between first and last digit (if any)
  * 4. Remove non-digits from integer part
  * 5. Remove non-digits from decimal part (optional)
  * 6. Try to match negative prefix before first digit
  * 7. Try to match negative suffix after last digit
  *
  * @param string $numberToParse Number to be parsed
  * @param array $parsedFormat Parsed format (from NumbersReader)
  * @param array $localizedSymbols An array with symbols to use
  * @return mixed Parsed float number or FALSE on failure
  */
 protected function doParsingInLenientMode($numberToParse, array $parsedFormat, array $localizedSymbols)
 {
     $numberIsNegative = FALSE;
     $positionOfFirstDigit = NULL;
     $positionOfLastDigit = NULL;
     $charactersOfNumberString = str_split($numberToParse);
     foreach ($charactersOfNumberString as $position => $character) {
         if (ord($character) >= 48 && ord($character) <= 57) {
             $positionOfFirstDigit = $position;
             break;
         }
     }
     if ($positionOfFirstDigit === NULL) {
         return FALSE;
     }
     krsort($charactersOfNumberString);
     foreach ($charactersOfNumberString as $position => $character) {
         if (ord($character) >= 48 && ord($character) <= 57) {
             $positionOfLastDigit = $position;
             break;
         }
     }
     $positionOfDecimalSeparator = strrpos($numberToParse, $localizedSymbols['decimal'], $positionOfFirstDigit);
     if ($positionOfDecimalSeparator === FALSE) {
         $integerPart = substr($numberToParse, $positionOfFirstDigit, $positionOfLastDigit - $positionOfFirstDigit + 1);
         $decimalPart = FALSE;
     } else {
         $integerPart = substr($numberToParse, $positionOfFirstDigit, $positionOfDecimalSeparator - $positionOfFirstDigit);
         $decimalPart = substr($numberToParse, $positionOfDecimalSeparator + 1, $positionOfLastDigit - $positionOfDecimalSeparator);
     }
     $parsedNumber = (int) preg_replace(self::PATTERN_MATCH_NOT_DIGITS, '', $integerPart);
     if ($decimalPart !== FALSE) {
         $decimalPart = (int) preg_replace(self::PATTERN_MATCH_NOT_DIGITS, '', $decimalPart);
         $parsedNumber = (double) ($parsedNumber . '.' . $decimalPart);
     }
     $partBeforeNumber = substr($numberToParse, 0, $positionOfFirstDigit);
     $partAfterNumber = substr($numberToParse, -(strlen($numberToParse) - $positionOfLastDigit - 1));
     if (!empty($parsedFormat['negativePrefix']) && !empty($parsedFormat['negativeSuffix'])) {
         if (\TYPO3\FLOW3\I18n\Utility::stringEndsWith($partBeforeNumber, $parsedFormat['negativePrefix']) && \TYPO3\FLOW3\I18n\Utility::stringBeginsWith($partAfterNumber, $parsedFormat['negativeSuffix'])) {
             $numberIsNegative = TRUE;
         }
     } elseif (!empty($parsedFormat['negativePrefix']) && \TYPO3\FLOW3\I18n\Utility::stringEndsWith($partBeforeNumber, $parsedFormat['negativePrefix'])) {
         $numberIsNegative = TRUE;
     } elseif (!empty($parsedFormat['negativeSuffix']) && \TYPO3\FLOW3\I18n\Utility::stringBeginsWith($partAfterNumber, $parsedFormat['negativeSuffix'])) {
         $numberIsNegative = TRUE;
     }
     $parsedNumber /= $parsedFormat['multiplier'];
     if ($numberIsNegative) {
         $parsedNumber = 0 - $parsedNumber;
     }
     return $parsedNumber;
 }
Пример #3
0
 /**
  * @test
  * @dataProvider sampleHaystackStringsAndNeedleStrings
  */
 public function stringIsFoundAtBeginningOfAnotherString($haystack, $needle, $comparison)
 {
     $expectedResult = $comparison === 'beginning' || $comparison === 'both' ? TRUE : FALSE;
     $result = \TYPO3\FLOW3\I18n\Utility::stringBeginsWith($haystack, $needle);
     $this->assertEquals($expectedResult, $result);
 }