The Gunning Fog Index, published by Robert Gunning in 1952, estimates how hard a passage is to read from two signals: long sentences and long words. This page breaks the formula into steps, explains the heuristics in the code below, shows a more robust implementation, and describes where readability scores are useful in search and RAG systems.
The Gunning Fog Index is a readability test that estimates the years of formal education needed to understand a text on the first reading. It takes into account the number of words, the number of complex words (words with three or more syllables), and the number of sentences in a text.import re
def count_words(text):
"""Counts the number of words in a text."""
words = re.findall(r'\w+', text)
return len(words)
def count_sentences(text):
"""Counts the number of sentences in a text."""
sentences = re.split(r'[.!?]+', text)
return len(sentences) - 1 if text[-1] in '.!?' else len(sentences)
def count_complex_words(text):
"""Counts the number of complex words in a text (words with three or more syllables)."""
def syllable_count(word):
word = word.lower()
vowels = "aeiouy"
count = 0
if word[0] in vowels:
count += 1
for index in range(1, len(word)):
if word[index] in vowels and word[index - 1] not in vowels:
count += 1
if word.endswith("e"):
count -= 1
if count == 0:
count += 1
return count
words = re.findall(r'\w+', text)
complex_words = [word for word in words if syllable_count(word) >= 3]
return len(complex_words)
def gunning_fog_index(text):
"""Calculates the Gunning Fog Index for a given text."""
num_words = count_words(text)
num_sentences = count_sentences(text)
num_complex_words = count_complex_words(text)
if num_sentences == 0:
return 0 # Avoid division by zero
average_sentence_length = num_words / num_sentences
percentage_complex_words = (num_complex_words / num_words) * 100
fog_index = 0.4 * (average_sentence_length + percentage_complex_words)
return fog_index
# Example usage
text = (
"The Gunning Fog Index is a readability test for English writing. "
"It estimates the years of formal education needed to understand the text on the first reading. "
"Complex words are those with three or more syllables."
)
fog_index = gunning_fog_index(text)
print(f"The Gunning Fog Index for the given text is: {fog_index:.2f}")
The Gunning Fog Index is a readability test that estimates the years of formal education needed to understand a text on the first reading. The implementation calculates the Gunning Fog Index using the following steps:
syllable_count function estimates the number of syllables in a word by analyzing vowel patterns.0.4 * (average sentence length + percentage of complex words).
Usage:
This implementation provides a way to rank texts based on readability using the Gunning Fog Index, which is useful in various Natural Language Processing (NLP) applications such as document analysis, content creation, and education.
The index is 0.4 x (average sentence length + percentage of complex words). Average sentence length is words divided by sentences. A complex word has three or more syllables; Gunning's original guidance excludes proper nouns, familiar compound words, and words that only reach three syllables through common suffixes such as -es, -ed or -ing. Most software implementations, including the one on this page, skip those exclusions and simply count syllables, which tends to push scores slightly higher.
Example: a 100-word passage with 5 sentences and 12 complex words gives 0.4 x (20 + 12) = 12.8, roughly the reading level of a high-school senior.
Popular newspapers and consumer documentation usually aim for 8 to 12. Technical documentation and legal text commonly score 15 or more. The score measures surface features only: a short, simple-word sentence about an unfamiliar concept can score low and still be hard to understand, and the index says nothing about structure, jargon that happens to be short, or correctness.
The sample code counts syllables by counting vowel groups and subtracting a trailing e. That heuristic is reasonable but miscounts words like table (it returns 1). Using a pronunciation dictionary where available and a heuristic as fallback improves accuracy:
import re
try:
import pyphen # pip install pyphen (hyphenation dictionaries)
_dic = pyphen.Pyphen(lang="en_US")
def syllables(w):
return max(1, len(_dic.inserted(w).split("-")))
except ImportError:
def syllables(w):
w = w.lower()
groups = re.findall(r"[aeiouy]+", w)
n = len(groups)
if w.endswith("e") and not w.endswith("le") and n > 1:
n -= 1
return max(1, n)
def gunning_fog(text: str) -> float:
sentences = [s for s in re.split(r"[.!?]+\s*", text) if s.strip()]
words = re.findall(r"[A-Za-z]+(?:'[a-z]+)?", text)
if not sentences or not words:
return 0.0
complex_ = [w for w in words
if syllables(w) >= 3 and not w[0].isupper()
and not re.search(r"(es|ed|ing)$", w)]
return 0.4 * (len(words) / len(sentences) + 100 * len(complex_) / len(words))
print(round(gunning_fog("The cat sat on the mat. It was happy."), 1))
print(round(gunning_fog("Organizational interoperability necessitates comprehensive documentation."), 1))The textstat package provides textstat.gunning_fog() along with Flesch, SMOG and other indices if you prefer a maintained library.
| Metric | Inputs | Output |
|---|---|---|
| Gunning Fog | Sentence length, 3+ syllable words | Grade level |
| Flesch Reading Ease | Sentence length, syllables per word | 0 to 100, higher is easier |
| Flesch-Kincaid Grade | Same as Flesch | Grade level |
| SMOG | Polysyllables in 30 sentences | Grade level, used in health literature |
| Coleman-Liau | Characters per word | Grade level, no syllable counting |
In retrieval systems readability scores are cheap features. They can flag boilerplate or garbled extraction (OCR noise produces extreme scores), help route queries to simpler or more technical sources, or check that generated answers meet a target reading level for a patient-facing or customer-facing product. They should be a filter or a ranking signal among many, never the only judge of quality.