Get a excerpt from a string by a neddle postion and its length

@param string $text
@param int $needlePosition
@param int $needleLength
@param int $contextLength
@return string
337334
static function getExcerpt(String $text, int $needlePosition, int $needleLength, int $contextLength) : string
    {
        $left = max($needlePosition - $contextLength, 0);
        $bufferLength = $needleLength + (2 * $contextLength);

        if($needleLength + $contextLength + $needlePosition > strlen($text)) {
            $text = substr($text, $left);
        } else {
            $text = substr($text, $left, $bufferLength);
        }

        return $text;
    }
1123753
def extract_with_context(lst, pred, before_context, after_context):
    
    rval = []

    start = 0
    length = 0
    while start < len(lst):
        usedfirst = False
        usedlast = False
        # Extend to the next match.
        while start + length < len(lst) and length < before_context + 1 \
                and not pred(lst[start + length]):
            length += 1

        # Slide to the next match.
        while start + length < len(lst) and not pred(lst[start + length]):
            start += 1

        # If there was no next match, abort here (it's easier
        # to do this than to try to detect this case later).
        if start + length == len(lst):
            break

        # Now extend repeatedly until we can't find anything.
        while start + length < len(lst) and pred(lst[start + length]):
            extendlength = 1
            # Read in the 'after' context and see if it holds a URL.
            while extendlength < after_context + 1 and start + length + \
                    extendlength < len(lst) and \
                    not pred(lst[start + length + extendlength]):
                extendlength += 1
            length += extendlength
            if start + length < len(lst) and not pred(lst[start + length]):
                # Didn't find a matching line, so we either
                # hit the end or extended to after_context + 1..
                #
                # Now read in possible 'before' context
                # from the next URL; if we don't find one,
                # we discard the readahead.
                extendlength = 1
                while extendlength < before_context and start + length + \
                        extendlength < len(lst) and \
                        not pred(lst[start + length + extendlength]):
                    extendlength += 1
                if start + length + extendlength < len(lst) and \
                        pred(lst[start + length + extendlength]):
                    length += extendlength

        if length > 0 and start + length <= len(lst):
            if start == 0:
                usedfirst = True
            if start + length == len(lst):
                usedlast = True
            rval.append((lst[start:start + length], usedfirst, usedlast))

        start += length
        length = 0
    return rval
854756
public function getExcerpt($length = 200, $includeTitle = false, $focus = null, $stripFields = [])
    {
        $title = null;
        if ($includeTitle && $this->title !== null) {
            $title = Html::trimText(strip_tags($this->title), $length);
            $length -= strlen($title);
        }

        if ($this->body instanceof Content) {
            $this->body = $this->body->toArray();
        }

        if ($this->body instanceof LegacyContent) {
            $this->body = $this->body->getValues();
        }

        if (!is_array($stripFields)) {
            trigger_error(sprintf('Wrong type for "stripField" parameter. Expected array, got %s. Ignoring "stripField".', gettype($stripFields)), E_USER_DEPRECATED);
            $stripFields = [];
        }

        if (is_array($this->body)) {
            // Assume it's an array, strip some common
            // fields that we don't need, merge with
            // the unwanted fields , implode the rest.
            $stripKeys = array_merge([
                'id',
                'slug',
                'datepublish',
                'datedepublish',
                'datecreated',
                'datechanged',
                'username',
                'ownerid',
                'title',
                'contenttype',
                'status',
                'taxonomy',
                'templatefields',
                'sortorder',
            ], $stripFields);

            $excerpt = '';
            array_walk($this->body, function ($value, $key) use (&$excerpt, $stripKeys) {
                if (in_array($key, $stripKeys)) {
                    return;
                }
                // We need non-empty strings that don't look like serialized JSON.
                // Otherwise, Twig Markup is also OK.
                if (is_string($value) && !empty($value) && !in_array($value[0], ['{', '[']) ||
                    $value instanceof Markup) {
                    $excerpt .= (string) $value . ' ';
                }
            });
        } elseif (is_string($this->body) || (is_object($this->body) && method_exists($this->body, '__toString'))) {
            // otherwise we just use the string.
            $excerpt = (string) $this->body;
        } else {
            // Nope, got nothing.
            $excerpt = '';
        }

        $excerpt = str_replace('>', '> ', $excerpt);

        if (empty($focus)) {
            $excerpt = Html::trimText(strip_tags($excerpt), $length);
        } else {
            $excerpt = $this->extractRelevant($focus, strip_tags($excerpt), $length);
        }

        if (!empty($title)) {
            $excerpt = '<b>' . $title . '</b> ' . $excerpt;
        }

        return trim($excerpt);
    }
861516
private void  extractRawText(TextContainer parent, StringBuilder str)
   {
      Iterator<SvgObject>  iter = parent.children.iterator();
      boolean              isFirstChild = true;

      while (iter.hasNext())
      {
         SvgObject  child = iter.next();

         if (child instanceof TextContainer) {
            extractRawText((TextContainer) child, str);
         } else if (child instanceof TextSequence) {
            str.append(textXMLSpaceTransform(((TextSequence) child).text, isFirstChild, !iter.hasNext() /*isLastChild*/));
         }
         isFirstChild = false;
      }
   }
878876
static function markString(string $text, int $position, int $length, array $mark) : string
    {
        $text = substr_replace($text, $mark[0], $position, 0);
        $text = substr_replace($text, $mark[1], $position + $length + strlen($mark[0]), 0);

        return $text;
    }
581990
public function prepare($text, $length = 100, $endString = '...')
    {
        $substring = strip_tags(preg_replace('/<br.?\/?>/', ' ',$text));
        $textLength = mb_strlen($substring);
        
        if($textLength > $length) {
            $lastWordPosition = mb_strpos($substring, ' ', $length);
            
            if($lastWordPosition) {
                $substring = mb_substr($substring, 0, $lastWordPosition);
            } else {
                $substring = mb_substr($substring, 0, $length);
            }
            
            $substring.= $endString;
        }
        
        return $substring;
    }
1107843
static int fixSelectionLength( String fullText, int selectionOffset, int selectionLength ) {

		if( selectionLength < 0 )
			selectionLength = 0;
		else if( selectionOffset + selectionLength > fullText.length())
			selectionLength = fullText.length() - selectionOffset;

		for( ; selectionOffset + selectionLength < fullText.length(); selectionLength ++ ) {
			char c = fullText.charAt( selectionOffset + selectionLength );
			if( isLineBreak( c ))
				break;
		}

		return selectionLength;
	}
541862
public static function resumeHtml($text, $nbCaracter, $readMoreText = '')
    {
        if (is_numeric($nbCaracter)) {
            $lengthBeforeWithoutHtml = strlen(trim(strip_tags($text)));
            $htmlSplitMask = '#</?([a-zA-Z1-6]+)(?: +[a-zA-Z]+="[^"]*")*( ?/)?>#';
            $htmlMatchMask = '#<(?:/([a-zA-Z1-6]+)|([a-zA-Z1-6]+)(?: +[a-zA-Z]+="[^"]*")*( ?/)?)>#';
            $text                   .= ' ';
            $textPieces = preg_split($htmlSplitMask, $text, -1, PREG_SPLIT_OFFSET_CAPTURE | PREG_SPLIT_NO_EMPTY);
            $pieceNumber = count($textPieces);

            if ($pieceNumber == 1) {
                $text        .= ' ';
                $lenghtBefore = strlen($text);
                $text = substr($text, 0, strpos($text, ' ', $lenghtBefore > $nbCaracter ? $nbCaracter : $lenghtBefore));

                if ($readMoreText != '' && $lenghtBefore > $nbCaracter) {
                    $text .= $readMoreText;
                }
            } else {
                $length = 0;
                $indexLastPiece = $pieceNumber - 1;
                $position = $textPieces[$indexLastPiece][1] + strlen($textPieces[$indexLastPiece][0]) - 1;
                $indexPiece = $indexLastPiece;
                $searchSpace = true;

                foreach ($textPieces as $index => $bout) {
                    $length += strlen($bout[0]);
                    if ($length >= $nbCaracter) {
                        $positionEndPiece = $bout[1] + strlen($bout[0]) - 1;
                        $position = $positionEndPiece - ($length - $nbCaracter);
                        if (($positionSpace = strpos($bout[0], ' ', $position - $bout[1])) !== false) {
                            $position = $bout[1] + $positionSpace;
                            $searchSpace = false;
                        }
                        if ($index != $indexLastPiece) {
                            $indexPiece = $index + 1;
                        }
                        break;
                    }
                }

                if ($searchSpace === true) {
                    for ($i = $indexPiece; $i <= $indexLastPiece; ++$i) {
                        $position = $textPieces[$i][1];
                        if (($positionSpace = strpos($textPieces[$i][0], ' ')) !== false) {
                            $position += $positionSpace;
                            break;
                        }
                    }
                }

                $text = substr($text, 0, $position);
                preg_match_all($htmlMatchMask, $text, $return, PREG_OFFSET_CAPTURE);
                $tagPieces = array();

                foreach ($return[0] as $index => $tag) {
                    if (isset($return[3][$index][0])) {
                        continue;
                    }
                    if ($return[0][$index][0][1] != '/') {
                        array_unshift($tagPieces, $return[2][$index][0]);
                    } else {
                        array_shift($tagPieces);
                    }
                }

                if (!empty($tagPieces)) {
                    foreach ($tagPieces as $tag) {
                        $text .= '</'.$tag.'>';
                    }
                }

                if ($readMoreText != '' && $lengthBeforeWithoutHtml > $nbCaracter) {
                    $text   .= 'SuspensionPoint';
                    $pattern = '#((</[^>]*>[\n\t\r ]*)?(</[^>]*>[\n\t\r ]*)?(</[^>]*>[\n\t\r ]*)?(</[^>]*>[\n\t\r ]*)?(</[^>]*>)[\n\t\r ]*SuspensionPoint)#i';
                    $text = preg_replace($pattern, $readMoreText.'${2}${3}${4}${5}${6}', $text);
                }
            }
        }

        return $text;
    }
573250
public function truncateHtmlText($text, $characters = 300)
    {
        // Clean up html tags and special characters
        $text = preg_replace('/<[^>]*>/', ' ', $text);
        $text = str_replace("\r", '', $text); // replace with empty space
        $text = str_replace("\n", ' ', $text); // replace with space
        $text = str_replace("\t", ' ', $text); // replace with space
        $text = preg_replace('/\s+/', ' ', $text); // remove multiple consecutive spaces
        $text = preg_replace('/^[\s]/', '', $text); // Remove leading space from excerpt
        $text = preg_replace('/[\s]$/', '', $text); // Remove trailing space from excerpt

        // If we are already within the limit, just return the text
        if (mb_strlen($text) <= $characters) {
            return $text;
        }

        // Truncate to character limit if longer than requested
        $text = substr($text, 0, $characters);

        // We don't want the string cut mid-word, so search for the last space and trim there
        $lastSpacePosition = strrpos($text, ' ');
        if (isset($lastSpacePosition)) {
            // Cut the text at this last word
            $text = substr($text, 0, $lastSpacePosition);
        }

        return $text;
    }
1030527
public static function parse($text, $context = null)
    {
        if (!static::$_enabled || strpos($text, '{') === false) {
            return $text;
        }

        if ($context === null) {
            $context = static::_getDefaultContext();
        }

        static::cache('context', $context);
        $pattern = static::_regex();

        return preg_replace_callback("/{$pattern}/s", 'static::_doShortcode', $text);
    }
302995
function _trimText(text, maxLength) {
  if(text) {
    text = text.toString();
    if(text.length > maxLength) {
      text = text.substr(0, maxLength - 1) + '..';
    }
  }
  return text;
}
1278009
public static function shorten($text, $maxlength = 140, $end = '[...]') {
        $maxlength++;
        if (mb_strlen($text) > $maxlength) {
            $subex = mb_substr($text, 0, $maxlength - 5);
            $exwords = explode(' ', $subex);
            $excut = - (mb_strlen($exwords[count($exwords)-1]));
            if ($excut < 0) {
                $text = mb_substr($subex, 0, $excut);
            } else {
                $text = $subex;
            }
            $text .= $end;
        }
        return $text;
    }
729375
function getGettextPluralPosition(ext, suffix) {
  if (ext) {
    for (let i = 0; i < ext.nplurals; i += 1) {
      if (i === suffix) {
        return i;
      }
    }
  }

  return -1;
}
756441
def textConcat(self, content, len):
        
        ret = libxml2mod.xmlTextConcat(self._o, content, len)
        return ret
954147
private String excerpt(String str, int maxLength) {
        return str.length() > maxLength ? excerptPattern.matcher(
                str.substring(0, maxLength)).replaceFirst("&hellip;") : str;
    }
994358
private function parseContent($text) {
        /* $yAlreadySet has 3 states: */
        /* null: There is no variable in the ID; true: the variable is already set; false: the variable is not set yet; */
        $content = null;
        $yAlreadySet = null;
        $realNameId = null;
        $separatorsFound = 0;
        $checksumAdded = 0;
        $decimalPointRemoved = 0;
        $toParse = str_replace('~F1', chr(29), $text);
        $nbCharToParse = strlen($toParse);
        $nbCharId = 0;
        $isFormated = $toParse[0] === '(' ? true : false;
        $maxCharId = $isFormated ? self::MAX_ID_FORMATED : self::MAX_ID_NOT_FORMATED;
        $id = strtolower(substr($toParse, 0, min($maxCharId, $nbCharToParse)));
        $id = $isFormated ? $this->findIdFormated($id, $yAlreadySet, $realNameId) : $this->findIdNotFormated($id, $yAlreadySet, $realNameId);

        if ($id === false) {
            if ($this->allowsUnknownIdentifier === false) {
                return false;
            }

            $id = null;
            $nbCharId = 0;
            $content = $toParse;
        } else {
            $nbCharId = strlen($id) + ($isFormated ? 2 : 0);
            $n = min($this->identifiersAi[$realNameId][self::MAXLENGTH], $nbCharToParse);
            $content = substr($toParse, $nbCharId, $n);
        }

        if ($id !== null) {
            /* If we have an AI with an "y" var, we check if there is a decimal point in the next *MAXLENGTH* characters */
            /* if there is one, we take an extra character */
            if ($yAlreadySet !== null) {
                if (strpos($content, '.') !== false || strpos($content, ',') !== false) {
                    $n++;
                    if ($n <= $nbCharToParse) {
                        /* We take an extra char */
                        $content = substr($toParse, $nbCharId, $n);
                    }
                }
            }
        }

        /* We check for separator */
        $separator = strpos($content, chr(29));
        if ($separator !== false) {
            $content = substr($content, 0, $separator);
            $separatorsFound++;
        }

        if ($id !== null) {
            /* We check the conformity */
            if (!$this->checkConformity($content, $id, $realNameId)) {
                return false;
            }

            /* We check the checksum */
            if (!$this->checkChecksum($content, $id, $realNameId, $checksumAdded)) {
                return false;
            }

            /* We check the vars */
            if (!$this->checkVars($content, $id, $yAlreadySet, $decimalPointRemoved)) {
                return false;
            }
        }

        $this->identifiersId[] = $id;
        $this->identifiersContent[] = $content;

        $nbCharLastContent = (((strlen($content) + $nbCharId) - $checksumAdded) + $decimalPointRemoved) + $separatorsFound;
        if ($nbCharToParse - $nbCharLastContent > 0) {
            /* If there is more than one content in this array, we parse again */
            $otherContent = substr($toParse, $nbCharLastContent, $nbCharToParse);
            $nbCharOtherContent = strlen($otherContent);

            if ($otherContent[0] === chr(29)) {
                $otherContent = substr($otherContent, 1);
                $nbCharOtherContent--;
            }

            if ($nbCharOtherContent > 0) {
                $text = $otherContent;
                return $this->parseContent($text);
            }
        }

        return true;
    }
258366
public function right($text, $length)
    {
        if (!$this->isValidLength($text, $length)) return $text;

        $textLength = strlen($text);

        return \substr($text, $textLength - $length, $textLength);
    }