$size ) { $piece = $this->cut_at_sentence( $paragraph, $size ); $raw[] = $piece; $paragraph = trim( self::slice( $paragraph, self::length( $piece ) ) ); } $buffer = $paragraph; } if ( '' !== $buffer ) { $raw[] = $buffer; } return $this->apply_overlap( $raw, $overlap ); } /** * Cut a long paragraph at the nearest sentence boundary. * * @param string $text The text. * @param int $size Maximum size. * @return string */ protected function cut_at_sentence( $text, $size ) { $window = self::slice( $text, 0, $size ); // Look for a sentence terminator in the last 30% of the window. $search_from = (int) ( $size * 0.7 ); $tail = self::slice( $window, $search_from ); if ( preg_match( '/^.*?[.!?…](?=\s|$)/us', $tail, $matches ) ) { return self::slice( $window, 0, $search_from + self::length( $matches[0] ) ); } return $window; } /** * Add overlap between adjacent chunks. * * @param array $chunks Raw chunks. * @param int $overlap Number of overlapping characters. * @return array */ protected function apply_overlap( $chunks, $overlap ) { if ( $overlap <= 0 || count( $chunks ) < 2 ) { return array_values( array_filter( $chunks, 'strlen' ) ); } $result = array(); $count = count( $chunks ); foreach ( $chunks as $index => $chunk ) { if ( 0 === $index ) { $result[] = $chunk; continue; } $previous = $chunks[ $index - 1 ]; $tail = self::slice( $previous, max( 0, self::length( $previous ) - $overlap ) ); $result[] = trim( $tail . "\n\n" . $chunk ); unset( $count ); } return array_values( array_filter( $result, 'strlen' ) ); } }