"'", // Left single quote "\xe2\x80\x99" => "'", // Right single quote "\xe2\x80\x9c" => '"', // Left double quote "\xe2\x80\x9d" => '"', // Right double quote "\xe2\x80\x93" => '-', // En dash "\xe2\x80\x94" => '-', // Em dash ); $text = strtr( $text, $smart_quotes ); // Decode HTML entities if any. $text = html_entity_decode( $text, ENT_QUOTES | ENT_HTML5, 'UTF-8' ); // Remove control characters except newlines/tabs. $text = preg_replace( '/[^\PC\s]/u', '', $text ); // Normalize line endings to LF. $text = str_replace( array( "\r\n", "\r" ), "\n", $text ); // Replace multiple spaces with a single space. $text = preg_replace( '/[ \t]+/u', ' ', $text ); // Replaces consecutive newlines with maximum two newlines (to preserve paragraphs). $text = preg_replace( '/\n{3,}/u', "\n\n", $text ); return trim( $text ); } /** * Approximate the token count of a string. * Handled via a hybrid calculation of characters and words: * (1 word = 1.33 tokens, 4 chars = 1 token). * * @param string $text Text to token count. * @return int Estimated token count. */ public static function count_tokens( string $text ): int { if ( empty( $text ) ) { return 0; } $word_count = str_word_count( $text ); $char_count = mb_strlen( $text, 'UTF-8' ); $token_by_words = (int) ceil( $word_count / 0.75 ); $token_by_chars = (int) ceil( $char_count / 4.0 ); // Return the max of the two estimates to avoid underestimating token usage limits. return max( $token_by_words, $token_by_chars ); } /** * Split text into sentences using standard regex. * * @param string $text Text to split. * @return array Array of sentences. */ public static function split_into_sentences( string $text ): array { if ( empty( $text ) ) { return array(); } // Regex pattern to split sentences without stripping punctuation. // Splits on '.', '!', or '?' followed by whitespace, keeping the punctuation attached. $sentences = preg_split( '/(?<=[.!?])\s+/u', $text, -1, PREG_SPLIT_NO_EMPTY ); if ( ! is_array( $sentences ) ) { return array( $text ); } return array_map( 'trim', $sentences ); } }