66 use ArrayAccess ;
77 use Countable ;
88 use Stringable ;
9+ use Tempest \Support \Arr \ImmutableArray ;
910 use Tempest \Support \Language ;
1011 use voku \helper \ASCII ;
1112
@@ -22,6 +23,19 @@ function to_title_case(Stringable|string $string): string
2223 return mb_convert_case ((string ) $ string , mode: MB_CASE_TITLE , encoding: 'UTF-8 ' );
2324 }
2425
26+ /**
27+ * Converts the given string to a naive sentence case. This doesn't detect proper nouns and proper adjectives that should stay capitalized.
28+ */
29+ function to_sentence_case (Stringable |string $ string ): string
30+ {
31+ $ words = array_map (
32+ callback: fn (string $ string ) => to_lower_case ($ string ),
33+ array: to_words ($ string ),
34+ );
35+
36+ return upper_first (implode (' ' , $ words ));
37+ }
38+
2539 /**
2640 * Converts the given string to lower case.
2741 */
@@ -51,17 +65,35 @@ function to_snake_case(Stringable|string $string, Stringable|string $delimiter =
5165 }
5266
5367 $ string = preg_replace ('/(.)(?=[A-Z])/u ' , '$1 ' . $ delimiter , $ string );
54- $ string = preg_replace (
55- '![^ ' . preg_quote ($ delimiter ) . '\pL\pN\s]+!u ' ,
56- $ delimiter ,
57- mb_strtolower ($ string , 'UTF-8 ' ),
58- );
68+ $ string = preg_replace ('![^ ' . preg_quote ($ delimiter ) . '\pL\pN\s]+!u ' , $ delimiter , mb_strtolower ($ string , 'UTF-8 ' ));
5969 $ string = preg_replace ('/\s+/u ' , $ delimiter , $ string );
6070 $ string = trim ($ string , $ delimiter );
6171
6272 return deduplicate ($ string , $ delimiter );
6373 }
6474
75+ /**
76+ * Returns an array of words from the specified string.
77+ * This is more accurate than {@see str_word_count()}.
78+ */
79+ function to_words (Stringable |string $ string ): array
80+ {
81+ // Remove 'words' that don't consist of alphanumerical characters or punctuation
82+ $ words = trim (preg_replace ("#[^(\w|\d|\'| \"|\.|\!|\?|;|,| \\|\/|\-|:|\&|@)]+# " , ' ' , (string ) $ string ));
83+ // Remove one-letter 'words' that consist only of punctuation
84+ $ words = trim (preg_replace ("#\s*[(\'| \"|\.|\!|\?|;|,| \\|\/|\-|:|\&|@)]\s*# " , ' ' , $ words ));
85+
86+ return array_values (array_filter (explode (' ' , namespace \deduplicate ($ words ))));
87+ }
88+
89+ /**
90+ * Counts the number of words in the given string.
91+ */
92+ function word_count (Stringable |string $ string ): int
93+ {
94+ return count (to_words ($ string ));
95+ }
96+
6597 /**
6698 * Converts the given string to kebab case.
6799 */
0 commit comments