Bonus chapter

Word Count Challenge

👋 Anyone can read and edit this exercise. Sign up to save your progress.

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.

Optional Challenge: Longer Words

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.

Exercise 1 of 2
Open in Web Editor

Results

    Compiler / runtime output
    
                
    Reveal the full solution Spoiler: the complete answer
    /// 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);
    }
    

    Optional Challenge: Consecutive Long Words

    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.

    Exercise 2 of 2
    Open in Web Editor

    Results

      Compiler / runtime output
      
                  
      Stuck? Show a hint No spoilers, just a nudge

      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?

      Reveal the full solution Spoiler: the complete answer
      /// 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);
      }
      
      Next chapter 8Enums and Pattern Matching

      Optional Chapters

      Extra practice to explore at your own pace. These chapters do not count toward course progress.