Word-pattern filters are useful for word games, vocabulary tools, and small text-processing projects. In this tutorial, we will build a simple five-letter word filter using plain JavaScript without a framework or external API.
The filter will support three conditions:
- A five-character pattern using
?for unknown positions - Letters that must occur in the word
- Letters that must not occur in the word
Creating a Sample Word List
We will start with a small array of five-letter words:
const words = [
"brain",
"brave",
"bread",
"chase",
"crane",
"crate",
"crave",
"dream",
"flame",
"grace",
"grain",
"place",
"plane",
"share",
"stone"
];
A production tool would normally use a much larger and carefully validated word list, but this sample is enough to demonstrate the filtering logic.
Matching a Word Pattern
Suppose the user enters this pattern:
c?a?e
The known positions are:
-
cin the first position -
ain the third position -
ein the fifth position
Each ? represents an unknown letter.
We can compare a word with the pattern using every():
function matchesPattern(word, pattern) {
return [...pattern].every((character, index) => {
return character === "?" || word[index] === character;
});
}
Calling the function with crane returns true:
matchesPattern("crane", "c?a?e");
However, a word such as chase returns false because its letter positions do not satisfy the complete pattern.
Checking Required Letters
Required letters must occur somewhere in the candidate word. Their positions do not need to be known.
function hasRequiredLetters(word, requiredLetters) {
return requiredLetters.every((letter) => word.includes(letter));
}
Before calling the function, we can convert the user’s input into an array:
const requiredLetters = [...new Set("ar".toLowerCase())];
Using Set prevents the same letter from being checked unnecessarily when it is entered more than once.
Removing Excluded Letters
The excluded-letter condition works in the opposite way. A candidate is valid only when none of the excluded letters occur in it.
function avoidsExcludedLetters(word, excludedLetters) {
return excludedLetters.every((letter) => !word.includes(letter));
}
For example:
const excludedLetters = [...new Set("bts".toLowerCase())];
Any word containing b, t, or s will now be removed.
Combining the Conditions
We can combine all three checks inside one filtering function:
function filterWords(words, pattern, required, excluded) {
const normalizedPattern = pattern.toLowerCase().trim();
const requiredLetters = [...new Set(required.toLowerCase())];
const excludedLetters = [...new Set(excluded.toLowerCase())];
if (!/^[a-z?]{5}$/.test(normalizedPattern)) {
throw new Error(
"The pattern must contain exactly five letters or question marks."
);
}
return words.filter((word) => {
return (
matchesPattern(word, normalizedPattern) &&
hasRequiredLetters(word, requiredLetters) &&
avoidsExcludedLetters(word, excludedLetters)
);
});
}
We can now test the filter:
const matches = filterWords(
words,
"c?a?e",
"r",
"bts"
);
console.log(matches);
The resulting array contains words that satisfy every condition.
Handling User Input Safely
Inputs should be normalized before filtering. Spaces, numbers, punctuation, and other unexpected characters can be removed from letter fields:
function cleanLetters(value) {
return value.toLowerCase().replace(/[^a-z]/g, "");
}
Clear validation messages should also be displayed when:
- The pattern contains fewer or more than five characters
- Unsupported characters are entered
- No words satisfy the selected conditions
This gives users useful feedback instead of silently returning an empty result.
Performance
The filter checks each word once, so its basic time complexity is O(n), where n is the number of words in the dataset. This is efficient enough for a typical browser-based word list.
For much larger datasets, possible improvements include:
- Pre-grouping words by length
- Creating indexes for starting and ending letters
- Caching repeated searches
- Loading data only when required
- Moving intensive processing to a Web Worker
Next Steps
This basic implementation can be extended with fixed-position exclusions, repeated-letter rules, sorting, frequency information, and scoring systems.
If you want to compare the JavaScript approach with a working interface containing more filtering options, the WordHubPro five-letter word finder provides an interactive example.
The most important lesson is to keep each filtering condition separate. Small, focused functions are easier to understand, test, and improve than one large block of filtering logic.
Top comments (0)