A word can have more than three bytes without having more than three Unicode scalar values. These optional challenges build on Word Count with strings, loops, conditionals, and borrowed text. First count all qualifying words, then find the longest run of consecutive qualifying words. Neither exercise counts toward course completion.
Both use the same rules. Words are separated by whitespace, including tabs,
newlines, and Unicode whitespace. Punctuation stays part of a word, so "cat!"
has four scalar values and qualifies. Count Unicode scalar values (chars), not
bytes or visible characters.
Each exercise has its own function and tests and can run without completing the other.
Write count_long_words(text) to count whitespace-separated words containing
more than three Unicode scalar values (chars). Use what you've learned so far,
without an implementation recipe.
Exactly three does not qualify. Count scalar values, not bytes or visible
characters: "été" has three, while "café" has four. Whitespace separates
words, including tabs, newlines, and Unicode whitespace. Punctuation stays part
of a word, so "cat!" qualifies. An empty or whitespace-only input has no
qualifying words.
/// Counts whitespace-separated words containing more than three Unicode scalar
/// values.
fn count_long_words(text: &str) -> usize {
let mut count = 0;
for word in text.split_whitespace() {
if word.chars().count() > 3 {
count += 1;
}
}
count
}
#[test]
fn test_empty_and_short_words() {
assert_eq!(count_long_words(""), 0);
assert_eq!(count_long_words(" \t\n"), 0);
assert_eq!(count_long_words("a to cat"), 0);
}
#[test]
fn test_long_words_and_whitespace() {
assert_eq!(count_long_words("one four\tfive\nseven"), 3);
}
#[test]
fn test_unicode_whitespace_separates_words() {
assert_eq!(count_long_words("four\u{2003}five"), 2);
}
#[test]
fn test_punctuation_remains_part_of_a_word() {
assert_eq!(count_long_words("cat!"), 1);
}
#[test]
fn test_unicode_scalar_values() {
assert_eq!(count_long_words("été café 猫猫猫 猫猫猫猫"), 2);
// The combining accent is a separate scalar value: a, b, e, accent.
assert_eq!(count_long_words("abe\u{301}"), 1);
}
Write longest_long_word_run(text) to return the largest number of consecutive
words containing more than three Unicode scalar values (chars). Count words in
the run, not the scalar values they contain. A word with three or fewer scalar
values breaks the run. Return 0 if no words qualify.
Words are separated by whitespace, including tabs, newlines, and Unicode
whitespace. Repeated whitespace does not introduce empty words or break a run.
Punctuation stays part of a word, so "cat!" qualifies. Count scalar values,
not bytes or visible characters: "été" has three, "café" has four, and
"abe\u{301}" has four because the combining accent is a separate scalar value.
Use loops and conditionals with borrowed text, as in Word Count. This file
stands on its own; you do not need your count_long_words implementation.
Once the tests pass, explain why counting all qualifying words would answer a different question.
Before writing code, consider how the current run can differ from the best run seen so far. What should survive when a short word ends a run?
/// Returns the greatest number of consecutive words with more than three
/// Unicode scalar values. Words are whitespace-separated, and punctuation
/// remains part of each word. A word with three or fewer scalar values breaks
/// the run; whitespace alone does not. Returns 0 when no words qualify.
fn longest_long_word_run(text: &str) -> usize {
let mut current = 0;
let mut best = 0;
for word in text.split_whitespace() {
if word.chars().count() > 3 {
current += 1;
if current > best {
best = current;
}
} else {
current = 0;
}
}
best
}
#[test]
fn empty_and_short_words_have_no_run() {
assert_eq!(longest_long_word_run(""), 0);
assert_eq!(longest_long_word_run(" \t\n"), 0);
assert_eq!(longest_long_word_run("a to cat"), 0);
}
#[test]
fn short_words_separate_runs() {
assert_eq!(longest_long_word_run("four five a seven eight"), 2);
assert_eq!(longest_long_word_run("four cat five"), 1);
}
#[test]
fn best_run_can_end_before_the_last_word() {
assert_eq!(longest_long_word_run("four five seven a eight"), 3);
assert_eq!(longest_long_word_run("four five seven a"), 3);
}
#[test]
fn best_run_can_reach_the_end() {
assert_eq!(longest_long_word_run("a four five seven"), 3);
assert_eq!(longest_long_word_run("four a five seven eight"), 3);
assert_eq!(longest_long_word_run("four"), 1);
}
#[test]
fn whitespace_does_not_break_a_run() {
assert_eq!(longest_long_word_run(" four\t\tfive\nseven "), 3);
assert_eq!(longest_long_word_run("four\u{2003}five"), 2);
}
#[test]
fn scalar_values_determine_whether_a_word_qualifies() {
assert_eq!(longest_long_word_run("café été four"), 1);
assert_eq!(longest_long_word_run("猫猫猫 猫猫猫猫 four"), 2);
assert_eq!(longest_long_word_run("abe\u{301} four"), 2);
}
#[test]
fn punctuation_remains_part_of_a_word() {
assert_eq!(longest_long_word_run("cat! four"), 2);
assert_eq!(longest_long_word_run("four ! five"), 1);
}
Extra practice to explore at your own pace. These chapters do not count toward course progress.