Spelling suggester
Checks a line of text against a list of 352 common English words and suggests, for each word it does not know, the closest words by edit distance - insertions, deletions, substitutions and swaps of two neighbouring letters - the more common word first on a tie; suggests for a single word, and adds new words for the session.
Every screen below was recorded under CPython. When this page was built, the EML interpreter replayed each session from the same input and printed the same bytes.
About
Checks a line of text against a list of 352 common English words. For each word it does not know, it suggests the closest words in the list by edit distance. It also suggests for a single word, and new words can be added for the session.
main.eml- the menu, the questions and their checks, and what the screen showsspelling.eml- the edit distance, the words of a text, and suggestionswords.eml- the word list, most common words first
How each part works:
- The edit distance is the fewest one-letter insertions, deletions and substitutions, and swaps of two neighbouring letters, that turn one word into another. It is the Levenshtein table of the corpus case
edit-distancewith one more way into a cell, for a swap:tehis one edit fromthe, not two. (This "optimal string alignment" distance never edits a stretch twice, socais three edits fromabc.) - Only distances that matter are worked out in full: a word whose length differs by more than the limit is skipped at once.
- Suggestions are the words within 2 edits when checking a line (at most 3) and within 3 edits for a single word (at most 5), nearest first. Two words equally near go in the order of the list, which runs from the most common word down, so
tehsuggeststhebeforebeandto. - A word is a run of letters and apostrophes in any case; apostrophes at either end are dropped, so
don'tandit'sare single words and'quoted'isquoted. A word that appears several times is reported once, with how many times. - Added words go to the end of the list, so they rank after the built-in words they tie with; they last until the program ends.
What is checked: a line is at most 200 characters; a single word is letters with apostrophes only inside, at most 20 characters; a word already in the list is not added again. An empty answer cancels.
Sessions: sessions/basic.in checks a line with teh twice, quikc, jumpd and dogg, and a line with freind, langauge and becuase, suggests for wrld, finds The in the list, adds receive and Tomorrow, suggests for recieve (now receive first), checks a line that is all known words, and lists the added words; sessions/bad-input.in types menu choices that are not 1 to 5, an empty line, 201 characters, a line with no words, two words, x1 and a-b as one word, it's, a word with nothing near, the to add again, 'quote' and 21 letters, adds Don't, and checks a line with nothing near and a line with apostrophes.
Built on the verified corpus case edit-distance (the Levenshtein distance as a bottom-up table).
Recorded sessions
What the screen shows while someone uses the program. Each typed line appears after its prompt, the way a terminal shows it.
bad-input
interpreter: byte-equal
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> 0
Pick a number from 1 to 5.
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> abc
Pick a number from 1 to 5.
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> 6
Pick a number from 1 to 5.
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> 1
text>
Cancelled.
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> 1
text> word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word x
That line has 201 characters; at most 200. Type it again.
text> 123 + 456 = 579 !!!
No words in that line.
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> 2
word> two words
Type one word of letters (an apostrophe inside is fine), at most 20.
word> x1
Type one word of letters (an apostrophe inside is fine), at most 20.
word> a-b
Type one word of letters (an apostrophe inside is fine), at most 20.
word>
Cancelled.
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> 2
word> it's
Closest to 'it's':
its - 1 edit
it - 2 edits
is - 2 edits
the - 3 edits
to - 3 edits
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> 2
word> xyzzyq
Nothing in the word list is within 3 edits of 'xyzzyq'.
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> 4
No words added yet.
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> 3
word> the
'the' is already in the word list.
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> 3
word> 'quote'
Type one word of letters (an apostrophe inside is fine), at most 20.
word> abcdefghijklmnopqrstu
Type one word of letters (an apostrophe inside is fine), at most 20.
word> Don't
Added 'don't'; the word list now has 353 words.
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> 3
word>
Cancelled.
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> 1
text> zzzz qqq
2 words, 2 not in the word list:
zzzz -> nothing within 2 edits
qqq -> nothing within 2 edits
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> 1
text> 'Don't' panic, it's fine.
4 words, 3 not in the word list:
panic -> nothing within 2 edits
it's -> its, it, is
fine -> line, find, fire
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> 4
Added this session: don't.
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> 5
Bye.
What was typed (32 lines)
0
abc
6
1
1
word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word x
123 + 456 = 579 !!!
2
two words
x1
a-b
2
it's
2
xyzzyq
4
3
the
3
'quote'
abcdefghijklmnopqrstu
Don't
3
1
zzzz qqq
1
'Don't' panic, it's fine.
4
5
basic
interpreter: byte-equal
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> 1
text> Teh quikc brown fox jumpd over teh lazy dogg.
9 words, 4 not in the word list:
teh (2 times) -> the, be, to
quikc -> quick
jumpd -> jump, jumped
dogg -> dog, do, does
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> 1
text> My freind found the langauge hard becuase of spelling.
9 words, 3 not in the word list:
freind -> friend, find
langauge -> language
becuase -> because
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> 2
word> wrld
Closest to 'wrld':
world - 1 edit
will - 2 edits
would - 2 edits
well - 2 edits
told - 2 edits
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> 2
word> The
'the' is in the word list.
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> 3
word> receive
Added 'receive'; the word list now has 353 words.
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> 3
word> Tomorrow
Added 'tomorrow'; the word list now has 354 words.
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> 2
word> recieve
Closest to 'recieve':
receive - 1 edit
believe - 2 edits
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> 1
text> I will receive the book tomorrow.
All 6 words are in the word list.
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> 4
Added this session: receive and tomorrow.
== Spelling suggester ==
1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit
choice> 5
Bye.
What was typed (18 lines)
1
Teh quikc brown fox jumpd over teh lazy dogg.
1
My freind found the langauge hard becuase of spelling.
2
wrld
2
The
3
receive
3
Tomorrow
2
recieve
1
I will receive the book tomorrow.
4
5
Modules
The program as written, entry module first. Each module transpiles to its own Python file, which is what eml project run executes.
main.eml(entry)
eml# P028 spelling suggester: check a line of text against a word list, suggest
# the closest words by edit distance, and add new words for this session.
import words
import spelling
200 => longest_line
def trim(s):
0 => i
len(s) => j
while i < j and s[i] == " ":
i + 1 => i
while j > i and s[j - 1] == " ":
j - 1 => j
return s[i:j]
def listed(items):
"" => out
0 => i
while i < len(items):
if i > 0 and i == len(items) - 1:
out + " and " => out
elif i > 0:
out + ", " => out
out + items[i] => out
i + 1 => i
return out
def plural(n, word):
if n == 1:
return "1 " + word
return str(n) + " " + word + "s"
def one_word(s):
# The word in lower case if s is one word of letters (an apostrophe inside
# is fine), at most 20 characters; "" otherwise.
trim(s) => s
if s == "" or len(s) > 20:
return ""
spelling.words_of(s) => ws
if len(ws) != 1 or len(ws[0]) != len(s):
return ""
return ws[0]
def ask_word():
# A word, or "" when the answer is empty, which cancels.
while True:
input("word> ") => answer
if trim(answer) == "":
return ""
one_word(answer) => w
if w != "":
return w
"Type one word of letters (an apostrophe inside is fine), at most 20." ^0
def check(text, known, vocabulary):
spelling.words_of(text) => ws
if len(ws) == 0:
"No words in that line." ^0
return
[] => unknown
{} => times
for w in ws:
if not (w in known):
if w in times:
times[w] + 1 => times[w]
else:
1 => times[w]
unknown + [w] => unknown
if len(unknown) == 0:
("All " + plural(len(ws), "word") + " are in the word list.") ^0
return
(plural(len(ws), "word") + ", " + str(len(unknown)) + " not in the word list:") ^0
for w in unknown:
" " + w => line
if times[w] > 1:
line + " (" + str(times[w]) + " times)" => line
spelling.suggestions(w, vocabulary, 2, 3) => found
if len(found) == 0:
(line + " -> nothing within 2 edits") ^0
else:
"" => names
for f in found:
if names != "":
names + ", " => names
names + f[0] => names
(line + " -> " + names) ^0
def suggest(w, known, vocabulary):
if w in known:
("'" + w + "' is in the word list.") ^0
return
spelling.suggestions(w, vocabulary, 3, 5) => found
if len(found) == 0:
("Nothing in the word list is within 3 edits of '" + w + "'.") ^0
return
("Closest to '" + w + "':") ^0
for f in found:
(" " + f[0] + " - " + plural(f[1], "edit")) ^0
{} => known
[] => vocabulary
for w in words.common:
True => known[w]
vocabulary + [w] => vocabulary
[] => added
True => running
while running:
"" ^0
"== Spelling suggester ==" ^0
"1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit" ^0
trim(input("choice> ")) => choice
if choice == "1":
"" => text
True => asking
while asking:
input("text> ") => text
if len(text) > longest_line:
("That line has " + str(len(text)) + " characters; at most " + str(longest_line) + ". Type it again.") ^0
else:
False => asking
if trim(text) == "":
"Cancelled." ^0
else:
check(text, known, vocabulary)
elif choice == "2":
ask_word() => w
if w == "":
"Cancelled." ^0
else:
suggest(w, known, vocabulary)
elif choice == "3":
ask_word() => w
if w == "":
"Cancelled." ^0
elif w in known:
("'" + w + "' is already in the word list.") ^0
else:
True => known[w]
vocabulary + [w] => vocabulary
added + [w] => added
("Added '" + w + "'; the word list now has " + str(len(vocabulary)) + " words.") ^0
elif choice == "4":
if len(added) == 0:
"No words added yet." ^0
else:
("Added this session: " + listed(added) + ".") ^0
elif choice == "5":
False => running
else:
"Pick a number from 1 to 5." ^0
"Bye." ^0
Python projection (main.py)
import words
import spelling
longest_line = 200
def trim(s):
i = 0
j = len(s)
while i < j and s[i] == " ":
i = i + 1
while j > i and s[j - 1] == " ":
j = j - 1
return s[i:j]
def listed(items):
out = ""
i = 0
while i < len(items):
if i > 0 and i == len(items) - 1:
out = out + " and "
elif i > 0:
out = out + ", "
out = out + items[i]
i = i + 1
return out
def plural(n, word):
if n == 1:
return "1 " + word
return str(n) + " " + word + "s"
def one_word(s):
s = trim(s)
if s == "" or len(s) > 20:
return ""
ws = spelling.words_of(s)
if len(ws) != 1 or len(ws[0]) != len(s):
return ""
return ws[0]
def ask_word():
while True:
answer = input("word> ")
if trim(answer) == "":
return ""
w = one_word(answer)
if w != "":
return w
print("Type one word of letters (an apostrophe inside is fine), at most 20.")
def check(text, known, vocabulary):
ws = spelling.words_of(text)
if len(ws) == 0:
print("No words in that line.")
return
unknown = []
times = {}
for w in ws:
if not w in known:
if w in times:
times[w] = times[w] + 1
else:
times[w] = 1
unknown = unknown + [w]
if len(unknown) == 0:
print("All " + plural(len(ws), "word") + " are in the word list.")
return
print(plural(len(ws), "word") + ", " + str(len(unknown)) + " not in the word list:")
for w in unknown:
line = " " + w
if times[w] > 1:
line = line + " (" + str(times[w]) + " times)"
found = spelling.suggestions(w, vocabulary, 2, 3)
if len(found) == 0:
print(line + " -> nothing within 2 edits")
else:
names = ""
for f in found:
if names != "":
names = names + ", "
names = names + f[0]
print(line + " -> " + names)
def suggest(w, known, vocabulary):
if w in known:
print("'" + w + "' is in the word list.")
return
found = spelling.suggestions(w, vocabulary, 3, 5)
if len(found) == 0:
print("Nothing in the word list is within 3 edits of '" + w + "'.")
return
print("Closest to '" + w + "':")
for f in found:
print(" " + f[0] + " - " + plural(f[1], "edit"))
known = {}
vocabulary = []
for w in words.common:
known[w] = True
vocabulary = vocabulary + [w]
added = []
running = True
while running:
print("")
print("== Spelling suggester ==")
print("1) check a line 2) suggest for a word 3) add a word 4) added words 5) quit")
choice = trim(input("choice> "))
if choice == "1":
text = ""
asking = True
while asking:
text = input("text> ")
if len(text) > longest_line:
print("That line has " + str(len(text)) + " characters; at most " + str(longest_line) + ". Type it again.")
else:
asking = False
if trim(text) == "":
print("Cancelled.")
else:
check(text, known, vocabulary)
elif choice == "2":
w = ask_word()
if w == "":
print("Cancelled.")
else:
suggest(w, known, vocabulary)
elif choice == "3":
w = ask_word()
if w == "":
print("Cancelled.")
elif w in known:
print("'" + w + "' is already in the word list.")
else:
known[w] = True
vocabulary = vocabulary + [w]
added = added + [w]
print("Added '" + w + "'; the word list now has " + str(len(vocabulary)) + " words.")
elif choice == "4":
if len(added) == 0:
print("No words added yet.")
else:
print("Added this session: " + listed(added) + ".")
elif choice == "5":
running = False
else:
print("Pick a number from 1 to 5.")
print("Bye.")
spelling.eml
eml# P028 spelling suggester - edit distance, the words of a text, and
# suggestions.
"abcdefghijklmnopqrstuvwxyz" => small
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" => capital
def distance(a, b, limit):
# The fewest one-letter insertions, deletions and substitutions, and swaps
# of two neighbouring letters, that turn a into b - the Levenshtein table
# of the corpus case edit-distance with one more way into a cell (the
# "optimal string alignment" distance). Anything over limit comes back as
# limit + 1, at once when the lengths alone differ by more.
len(a) => n
len(b) => m
if n - m > limit or m - n > limit:
return limit + 1
[] => t
for i in [0:n]:
[0] * (m + 1) => row
i => row[0]
t + [row] => t
for j in [0:m]:
j => t[0][j]
for i in [1:n]:
for j in [1:m]:
1 => cost
if a[i - 1] == b[j - 1]:
0 => cost
t[i - 1][j] + 1 => best
if t[i][j - 1] + 1 < best:
t[i][j - 1] + 1 => best
if t[i - 1][j - 1] + cost < best:
t[i - 1][j - 1] + cost => best
if i > 1 and j > 1 and a[i - 1] == b[j - 2] and a[i - 2] == b[j - 1]:
if t[i - 2][j - 2] + 1 < best:
t[i - 2][j - 2] + 1 => best
best => t[i][j]
if t[n][m] > limit:
return limit + 1
return t[n][m]
def lower_letter(c):
# c in lower case if it is a letter, "'" for an apostrophe, else "".
if c == "'":
return c
0 => k
while k < 26:
if small[k] == c or capital[k] == c:
return small[k]
k + 1 => k
return ""
def without_apostrophes_around(w):
0 => i
len(w) => j
while i < j and w[i] == "'":
i + 1 => i
while j > i and w[j - 1] == "'":
j - 1 => j
return w[i:j]
def words_of(text):
# The words of a text in lower case: runs of letters and apostrophes, with
# apostrophes at either end dropped, so "don't" stays one word.
[] => out
"" => w
for c in text + " ":
lower_letter(c) => l
if l != "":
w + l => w
else:
without_apostrophes_around(w) => s
if s != "":
out + [s] => out
"" => w
return out
def suggestions(word, vocabulary, limit, most):
# Up to `most` words of the vocabulary within `limit` edits of word, as
# [word, edits] pairs, nearest first; between equally near words the one
# earlier in the vocabulary (the more common one) comes first.
[] => found
for w in vocabulary:
distance(word, w, limit) => d
if d <= limit:
len(found) => j
while j > 0 and found[j - 1][1] > d:
j - 1 => j
found[0:j] + [[w, d]] + found[j:len(found)] => found
if len(found) > most:
found[0:most] => found
return found
Python projection (spelling.py)
small = "abcdefghijklmnopqrstuvwxyz"
capital = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def distance(a, b, limit):
n = len(a)
m = len(b)
if n - m > limit or m - n > limit:
return limit + 1
t = []
for i in range(0, n+1):
row = [0] * (m + 1)
row[0] = i
t = t + [row]
for j in range(0, m+1):
t[0][j] = j
for i in range(1, n+1):
for j in range(1, m+1):
cost = 1
if a[i - 1] == b[j - 1]:
cost = 0
best = t[i - 1][j] + 1
if t[i][j - 1] + 1 < best:
best = t[i][j - 1] + 1
if t[i - 1][j - 1] + cost < best:
best = t[i - 1][j - 1] + cost
if i > 1 and j > 1 and a[i - 1] == b[j - 2] and a[i - 2] == b[j - 1]:
if t[i - 2][j - 2] + 1 < best:
best = t[i - 2][j - 2] + 1
t[i][j] = best
if t[n][m] > limit:
return limit + 1
return t[n][m]
def lower_letter(c):
if c == "'":
return c
k = 0
while k < 26:
if small[k] == c or capital[k] == c:
return small[k]
k = k + 1
return ""
def without_apostrophes_around(w):
i = 0
j = len(w)
while i < j and w[i] == "'":
i = i + 1
while j > i and w[j - 1] == "'":
j = j - 1
return w[i:j]
def words_of(text):
out = []
w = ""
for c in text + " ":
l = lower_letter(c)
if l != "":
w = w + l
else:
s = without_apostrophes_around(w)
if s != "":
out = out + [s]
w = ""
return out
def suggestions(word, vocabulary, limit, most):
found = []
for w in vocabulary:
d = distance(word, w, limit)
if d <= limit:
j = len(found)
while j > 0 and found[j - 1][1] > d:
j = j - 1
found = found[0:j] + [[w, d]] + found[j:len(found)]
if len(found) > most:
found = found[0:most]
return found
words.eml
eml# P028 spelling suggester - the built-in word list: 352 common English words,
# most common first. When two suggestions are the same number of edits away,
# the one that comes first here comes first.
[
"the", "be", "to", "of", "and", "a", "in", "that", "have", "i", "it",
"for", "not", "on", "with", "he", "as", "you", "do", "at", "this", "but",
"his", "by", "from", "they", "we", "say", "her", "she", "or", "an",
"will", "my", "one", "all", "would", "there", "their", "what", "so",
"up", "out", "if", "about", "who", "get", "which", "go", "me", "when",
"make", "can", "like", "time", "no", "just", "him", "know", "take",
"people", "into", "year", "your", "good", "some", "could", "them", "see",
"other", "than", "then", "now", "look", "only", "come", "its", "over",
"think", "also", "back", "after", "use", "two", "how", "our", "work",
"first", "well", "way", "even", "new", "want", "because", "any", "these",
"give", "day", "most", "us", "is", "was", "are", "been", "has", "had",
"were", "said", "did", "made", "went", "came", "saw", "got", "gave",
"took", "found", "told", "thought", "called", "asked", "going", "being",
"does", "done", "man", "men", "woman", "child", "children", "world",
"life", "hand", "part", "place", "case", "week", "point", "number",
"home", "water", "room", "mother", "father", "night", "thing", "things",
"name", "house", "book", "word", "words", "story", "school", "family",
"friend", "city", "country", "money", "eye", "eyes", "head", "face",
"door", "line", "end", "side", "kind", "group", "problem", "question",
"idea", "fact", "light", "song", "game", "paper", "picture", "letter",
"language", "sentence", "spelling", "great", "little", "old", "big",
"high", "different", "small", "large", "next", "early", "young",
"important", "few", "public", "bad", "same", "able", "last", "long",
"best", "better", "right", "left", "full", "fast", "quick", "quickly",
"brown", "lazy", "black", "white", "red", "green", "blue", "cold", "hot",
"hard", "easy", "real", "sure", "free", "find", "tell", "ask", "seem",
"feel", "try", "leave", "call", "keep", "let", "begin", "help", "talk",
"turn", "start", "show", "hear", "play", "run", "move", "live",
"believe", "hold", "bring", "happen", "write", "sit", "stand", "lose",
"pay", "meet", "include", "continue", "set", "learn", "change", "lead",
"understand", "watch", "follow", "stop", "create", "speak", "read",
"spend", "grow", "open", "walk", "win", "offer", "remember", "love",
"consider", "appear", "buy", "wait", "serve", "die", "send", "expect",
"build", "stay", "fall", "cut", "reach", "kill", "remain", "jump",
"jumped", "spell", "draw", "carry", "eat", "here", "where", "why",
"each", "between", "under", "never", "again", "always", "often", "still",
"once", "soon", "together", "without", "until", "while", "through",
"around", "below", "above", "against", "away", "down", "off", "too",
"very", "really", "almost", "enough", "every", "something", "sometimes",
"another", "such", "both", "own", "later", "dog", "fox", "cat", "bird",
"tree", "river", "sea", "earth", "fire", "food", "car", "street",
"state", "mile", "animal", "plant", "page", "list"
] => common
Python projection (words.py)
common = ["the", "be", "to", "of", "and", "a", "in", "that", "have", "i", "it", "for", "not", "on", "with", "he", "as", "you", "do", "at", "this", "but", "his", "by", "from", "they", "we", "say", "her", "she", "or", "an", "will", "my", "one", "all", "would", "there", "their", "what", "so", "up", "out", "if", "about", "who", "get", "which", "go", "me", "when", "make", "can", "like", "time", "no", "just", "him", "know", "take", "people", "into", "year", "your", "good", "some", "could", "them", "see", "other", "than", "then", "now", "look", "only", "come", "its", "over", "think", "also", "back", "after", "use", "two", "how", "our", "work", "first", "well", "way", "even", "new", "want", "because", "any", "these", "give", "day", "most", "us", "is", "was", "are", "been", "has", "had", "were", "said", "did", "made", "went", "came", "saw", "got", "gave", "took", "found", "told", "thought", "called", "asked", "going", "being", "does", "done", "man", "men", "woman", "child", "children", "world", "life", "hand", "part", "place", "case", "week", "point", "number", "home", "water", "room", "mother", "father", "night", "thing", "things", "name", "house", "book", "word", "words", "story", "school", "family", "friend", "city", "country", "money", "eye", "eyes", "head", "face", "door", "line", "end", "side", "kind", "group", "problem", "question", "idea", "fact", "light", "song", "game", "paper", "picture", "letter", "language", "sentence", "spelling", "great", "little", "old", "big", "high", "different", "small", "large", "next", "early", "young", "important", "few", "public", "bad", "same", "able", "last", "long", "best", "better", "right", "left", "full", "fast", "quick", "quickly", "brown", "lazy", "black", "white", "red", "green", "blue", "cold", "hot", "hard", "easy", "real", "sure", "free", "find", "tell", "ask", "seem", "feel", "try", "leave", "call", "keep", "let", "begin", "help", "talk", "turn", "start", "show", "hear", "play", "run", "move", "live", "believe", "hold", "bring", "happen", "write", "sit", "stand", "lose", "pay", "meet", "include", "continue", "set", "learn", "change", "lead", "understand", "watch", "follow", "stop", "create", "speak", "read", "spend", "grow", "open", "walk", "win", "offer", "remember", "love", "consider", "appear", "buy", "wait", "serve", "die", "send", "expect", "build", "stay", "fall", "cut", "reach", "kill", "remain", "jump", "jumped", "spell", "draw", "carry", "eat", "here", "where", "why", "each", "between", "under", "never", "again", "always", "often", "still", "once", "soon", "together", "without", "until", "while", "through", "around", "below", "above", "against", "away", "down", "off", "too", "very", "really", "almost", "enough", "every", "something", "sometimes", "another", "such", "both", "own", "later", "dog", "fox", "cat", "bird", "tree", "river", "sea", "earth", "fire", "food", "car", "street", "state", "mile", "animal", "plant", "page", "list"]