original_string: protected static function _substr($text, $start, $length, array $options)
      {
          if (empty($options['trimWidth'])) {
              $substr = 'mb_substr';
          } else {
              $substr = 'mb_strimwidth';
          }
  
          $maxPosition = self::_strlen($text, ['trimWidth' => false] + $options);
          if ($start < 0) {
              $start += $maxPosition;
              if ($start < 0) {
                  $start = 0;
              }
          }
          if ($start >= $maxPosition) {
              return '';
          }
  
          if ($length === null) {
              $length = self::_strlen($text, $options);
          }
  
          if ($length < 0) {
              $text = self::_substr($text, $start, null, $options);
              $start = 0;
              $length += self::_strlen($text, $options);
          }
  
          if ($length <= 0) {
              return '';
          }
  
          if (empty($options['html'])) {
              return (string)$substr($text, $start, $length);
          }
  
          $totalOffset = 0;
          $totalLength = 0;
          $result = '';
  
          $pattern = '/(&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};)/i';
          $parts = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
          foreach ($parts as $part) {
              $offset = 0;
  
              if ($totalOffset < $start) {
                  $len = self::_strlen($part, ['trimWidth' => false] + $options);
                  if ($totalOffset + $len <= $start) {
                      $totalOffset += $len;
                      continue;
                  }
  
                  $offset = $start - $totalOffset;
                  $totalOffset = $start;
              }
  
              $len = self::_strlen($part, $options);
              if ($offset !== 0 || $totalLength + $len > $length) {
                  if (strpos($part, '&') === 0 && preg_match($pattern, $part)
                      && $part !== html_entity_decode($part, ENT_HTML5 | ENT_QUOTES, 'UTF-8')
                  ) {
                      // Entities cannot be passed substr.
                      continue;
                  }
  
                  $part = $substr($part, $offset, $length - $totalLength);
                  $len = self::_strlen($part, $options);
              }
  
              $result .= $part;
              $totalLength += $len;
              if ($totalLength >= $length) {
                  break;
              }
          }
  
          return $result;
      }
code: protected static function _substr($text, $start, $length, array $options)
      {
          if (empty($options['trimWidth'])) {
              $substr = 'mb_substr';
          } else {
              $substr = 'mb_strimwidth';
          }
  
          $maxPosition = self::_strlen($text, ['trimWidth' => false] + $options);
          if ($start < 0) {
              $start += $maxPosition;
              if ($start < 0) {
                  $start = 0;
              }
          }
          if ($start >= $maxPosition) {
              return '';
          }
  
          if ($length === null) {
              $length = self::_strlen($text, $options);
          }
  
          if ($length < 0) {
              $text = self::_substr($text, $start, null, $options);
              $start = 0;
              $length += self::_strlen($text, $options);
          }
  
          if ($length <= 0) {
              return '';
          }
  
          if (empty($options['html'])) {
              return (string)$substr($text, $start, $length);
          }
  
          $totalOffset = 0;
          $totalLength = 0;
          $result = '';
  
          $pattern = '/(&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};)/i';
          $parts = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
          foreach ($parts as $part) {
              $offset = 0;
  
              if ($totalOffset < $start) {
                  $len = self::_strlen($part, ['trimWidth' => false] + $options);
                  if ($totalOffset + $len <= $start) {
                      $totalOffset += $len;
                      continue;
                  }
  
                  $offset = $start - $totalOffset;
                  $totalOffset = $start;
              }
  
              $len = self::_strlen($part, $options);
              if ($offset !== 0 || $totalLength + $len > $length) {
                  if (strpos($part, '&') === 0 && preg_match($pattern, $part)
                      && $part !== html_entity_decode($part, ENT_HTML5 | ENT_QUOTES, 'UTF-8')
                  ) {
                      // Entities cannot be passed substr.
                      continue;
                  }
  
                  $part = $substr($part, $offset, $length - $totalLength);
                  $len = self::_strlen($part, $options);
              }
  
              $result .= $part;
              $totalLength += $len;
              if ($totalLength >= $length) {
                  break;
              }
          }
  
          return $result;
      }
code_tokens: protected static function _substr ( $ text , $ start , $ length , array $ options ) { if ( empty ( $ options [ 'trimWidth' ] ) ) { $ substr = 'mb_substr' ; } else { $ substr = 'mb_strimwidth' ; } $ maxPosition = self :: _strlen ( $ text , [ 'trimWidth' => false ] + $ options ) ; if ( $ start < 0 ) { $ start += $ maxPosition ; if ( $ start < 0 ) { $ start = 0 ; } } if ( $ start >= $ maxPosition ) { return '' ; } if ( $ length === null ) { $ length = self :: _strlen ( $ text , $ options ) ; } if ( $ length < 0 ) { $ text = self :: _substr ( $ text , $ start , null , $ options ) ; $ start = 0 ; $ length += self :: _strlen ( $ text , $ options ) ; } if ( $ length <= 0 ) { return '' ; } if ( empty ( $ options [ 'html' ] ) ) { return ( string ) $ substr ( $ text , $ start , $ length ) ; } $ totalOffset = 0 ; $ totalLength = 0 ; $ result = '' ; $ pattern = '/(&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};)/i' ; $ parts = preg_split ( $ pattern , $ text , - 1 , PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY ) ; foreach ( $ parts as $ part ) { $ offset = 0 ; if ( $ totalOffset < $ start ) { $ len = self :: _strlen ( $ part , [ 'trimWidth' => false ] + $ options ) ; if ( $ totalOffset + $ len <= $ start ) { $ totalOffset += $ len ; continue ; } $ offset = $ start - $ totalOffset ; $ totalOffset = $ start ; } $ len = self :: _strlen ( $ part , $ options ) ; if ( $ offset !== 0 || $ totalLength + $ len > $ length ) { if ( strpos ( $ part , '&' ) === 0 && preg_match ( $ pattern , $ part ) && $ part !== html_entity_decode ( $ part , ENT_HTML5 | ENT_QUOTES , 'UTF-8' ) ) { // Entities cannot be passed substr. continue ; } $ part = $ substr ( $ part , $ offset , $ length - $ totalLength ) ; $ len = self :: _strlen ( $ part , $ options ) ; } $ result .= $ part ; $ totalLength += $ len ; if ( $ totalLength >= $ length ) { break ; } } return $ result ; }
docstring: Return part of a string.
  
  ### Options:
  
  - `html` If true, HTML entities will be handled as decoded characters.
  - `trimWidth` If true, will be truncated with specified width.
  
  @param string $text The input string.
  @param int $start The position to begin extracting.
  @param int $length The desired length.
  @param array $options An array of options.
  @return string
docstring_tokens: Return part of a string .