# Words by the Numbers 7, Exercise 2 import pathlib, re, urllib.request BOOKS = {"Alice in Wonderland": 11, "The Time Machine": 35, "Pride and Prejudice": 1342, "The Federalist Papers": 1404} def load(number): path = pathlib.Path(f"pg{number}.txt") if not path.exists(): url = f"https://www.gutenberg.org/cache/epub/{number}/pg{number}.txt" req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"}) path.write_bytes(urllib.request.urlopen(req).read()) raw = path.read_text(encoding="utf-8-sig").replace("\r", "") start = raw.index("\n", raw.index("*** START OF")) + 1 return raw[start:raw.index("*** END OF")] def careful(word): w = re.sub(r"[^a-z]", "", word.lower()) if not w: return 0 n = len(re.findall(r"[aeiouy]+", w)) if w.endswith("e") and not w.endswith("le") and n > 1: n -= 1 if w.endswith("ed") and not w.endswith(("ted", "ded")) and n > 1: n -= 1 return max(n, 1) def naive(word): # just count the vowel runs return max(len(re.findall(r"[aeiouy]+", word.lower())), 1) def grade(text, counter): for fancy, plain in (("\u2019", "'"), ("\u201c", '"'), ("\u201d", '"')): text = text.replace(fancy, plain) text = re.sub(r"\s+", " ", text) sentences = [s for s in re.split(r"(?<=[.!?])[\"')\]]*\s+", text.strip()) if s] words = re.findall(r"[A-Za-z]+(?:'[A-Za-z]+)?", text) syl = sum(counter(w) for w in words) return 0.39 * len(words) / len(sentences) + 11.8 * syl / len(words) - 15.59 print(f"{'book':22} {'careful':>8} {'naive':>7} {'difference':>11}") for title, number in BOOKS.items(): text = load(number) a, b = grade(text, careful), grade(text, naive) print(f"{title:22} {a:8.2f} {b:7.2f} {b - a:11.2f}") # Output when run (Python 3.14; texts from the Project Gutenberg plain-text files): # book careful naive difference # Alice in Wonderland 5.97 7.46 1.49 # The Time Machine 7.46 9.01 1.55 # Pride and Prejudice 8.35 9.77 1.43 # The Federalist Papers 16.17 17.55 1.39