Sentence strings. */ public function split_sentences( string $text ): array { $text = trim( $text ); if ( '' === $text ) { return array(); } $protected = self::protect_abbreviations( $text ); // Split on sentence-ending punctuation followed by whitespace, OR newlines. $parts = preg_split( '/(?<=[.!?;])\s+|\R+/u', $protected ); if ( false === $parts ) { return array(); } $out = array(); foreach ( $parts as $part ) { $sentence = self::restore_abbreviations( $part ); $sentence = trim( $sentence, " \t\r\n.!?;" ); if ( '' !== $sentence ) { $out[] = $sentence; } } return $out; } /** * Splits a sentence into phrases. * * Phrases are separated by commas, colons, semicolons, em dashes, or * en dashes. Single-word "phrases" (artefacts of stray punctuation) * are dropped. * * @since 1.0.0 * * @param string $sentence A single sentence. * * @return array Phrase strings. */ public function split_phrases( string $sentence ): array { $sentence = trim( $sentence ); if ( '' === $sentence ) { return array(); } $parts = preg_split( '/[,;:\x{2014}\x{2013}]+/u', $sentence ); if ( false === $parts ) { return array( $sentence ); } $out = array(); foreach ( $parts as $part ) { $phrase = trim( $part ); if ( '' === $phrase ) { continue; } // Drop single-word fragments — they are artefacts of stray punctuation. if ( ! str_contains( $phrase, ' ' ) ) { continue; } $out[] = $phrase; } // If filtering left us with nothing, return the original sentence as // a single-phrase fallback so the caller always has at least one item. return array() === $out ? array( $sentence ) : $out; } /** * List of abbreviations whose trailing periods must not break sentences. * * @return array */ private static function abbreviations(): array { return array( 'Mr.', 'Mrs.', 'Ms.', 'Dr.', 'Prof.', 'St.', 'Sr.', 'Jr.', 'vs.', 'etc.', 'e.g.', 'i.e.', 'No.', 'p.m.', 'a.m.', ); } /** * Replaces abbreviation periods with a non-period placeholder. * * @since 1.0.0 * * @param string $text Input text. * * @return string Protected text. */ private static function protect_abbreviations( string $text ): string { $replacements = array(); foreach ( self::abbreviations() as $abbr ) { $replacements[ $abbr ] = str_replace( '.', '\u{2024}', $abbr ); // ONE DOT LEADER } return strtr( $text, $replacements ); } /** * Reverses the placeholder substitution applied by protect_abbreviations. * * @since 1.0.0 * * @param string $text Protected text. * * @return string Restored text. */ private static function restore_abbreviations( string $text ): string { return str_replace( '\u{2024}', '.', $text ); } }