@dcoffey/espells
Version:
Pure JS/TS spellchecker, using Hunspell dictionaries. Based on Spylls.
220 lines • 7.49 kB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import { CONSTANTS as C } from "./constants.js";
import { replaceRange, uppercase } from "./util.js";
/**
* Uses a {@link Aff}'s {@link RepPattern} table to yield replaced
* permutations of a word.
*
* @param word - The word to yield the replaced forms of.
* @param reps - The set of {@link RepPattern}s to use.
*/
export function* replchars(word, reps) {
if (word.length < 2 || !reps.size)
return;
for (const rep of reps) {
for (const suggestion of rep.replace(word)) {
yield suggestion;
if (suggestion.includes(" "))
yield suggestion.split(" ", 2);
}
}
}
/**
* Uses an {@link Aff}'s `MAP` table to recursively replace characters in a
* word. This yields every permutation of this action for every character.
*
* @param word - The word to yield the mapped forms of.
* @param map - The map to use.
*/
export function* mapchars(word, map) {
if (word.length < 2 || !map.size)
return;
function* mapcharsInternal(word, start = 0) {
if (start >= word.length)
return;
for (const options of map) {
for (const option of options) {
const pos = word.indexOf(option, start);
if (pos !== -1) {
for (const other of options) {
if (other === option)
continue;
const replaced = replaceRange(word, pos, pos + option.length, other);
yield replaced;
for (const variant of mapcharsInternal(replaced, pos + 1)) {
yield variant;
}
}
}
}
}
}
yield* mapcharsInternal(word);
}
/**
* Yields the permutations of a word with adjacent characters within it
* swapped. For short words, specifically 4-5 letters, doubleswaps will be
* yielded as well.
*/
export function* swapchar(word) {
if (word.length < 2)
return;
for (let i = 0; i < word.length - 1; i++) {
yield word.slice(0, i) + word[i + 1] + word[i] + word.slice(i + 2);
}
if (word.length === 4 || word.length === 5) {
yield word[1] +
word[0] +
(word.length === 5 ? word[2] : "") +
word.slice(-1) +
word.slice(-2);
if (word.length === 5) {
yield word[0] + word[2] + word[1] + word.slice(-1) + word.slice(-2);
}
}
}
/**
* Yields the permutations of a word where non-adjacent characters are
* swapped, with a maximum distance of four characters.
*/
export function* longswapchar(word) {
for (let first = 0; first < word.length - 2; first++) {
for (let second = first + 2; second < Math.min(first + C.MAX_CHAR_DISTANCE, word.length); second++) {
yield word.slice(0, first) +
word[second] +
word.slice(first + 1, second) +
word[first] +
word.slice(second + 1);
}
}
}
/**
* Yields the permutations of a word where characters are swapped with
* characters adjacent to it, but as found on a keyboard layout, not in the
* word itself. Additionally, variations on single character capitalization
* will be yielded.
*
* @param word - The word to yield the permutations of.
* @param layout - The layout string, with rows of the keyboard separated
* by `|` pipe characters.
*/
export function* badcharkey(word, layout) {
for (let i = 0; i < word.length; i++) {
const ch = word[i];
const before = word.slice(0, i);
const after = word.slice(i + 1);
if (ch !== uppercase(ch)) {
yield before + uppercase(ch) + after;
}
if (!layout)
continue;
let pos = layout.indexOf(ch);
while (pos !== -1) {
if (pos > 0 && layout[pos - 1] !== "|") {
yield before + layout[pos - 1] + after;
}
if (pos + 1 < layout.length && layout[pos + 1] !== "|") {
yield before + layout[pos - 1] + after;
}
pos = layout.indexOf(ch, pos + 1);
}
}
}
/**
* Yields the permutations of a word where a character has been removed
* from every position.
*/
export function* extrachar(word) {
if (word.length < 2)
return;
for (let i = 0; i < word.length; i++) {
yield word.slice(0, i) + word.slice(i + 1);
}
}
/**
* Yields the permutations of a word with a character inserted in every
* position, using a `TRY` string for determining which characters should
* be inserted.
*
* @param word - The word to yield of the permutations of.
* @param trystring - A string of characters which will be iterated through
* when inserting new characters.
*/
export function* forgotchar(word, trystring) {
if (!trystring)
return;
for (const ch of trystring) {
for (let i = 0; i < word.length + 1; i++) {
yield word.slice(0, i) + ch + word.slice(i);
}
}
}
/**
* Yields the permutations of a word where a character has been moved 2, 3,
* or 4 positions backwards or forwards.
*/
export function* movechar(word) {
if (word.length < 2)
return;
for (let frompos = 0; frompos < word.length; frompos++) {
const ch = word[frompos];
for (let topos = frompos + 3; topos < Math.min(word.length, frompos + C.MAX_CHAR_DISTANCE + 1); topos++) {
yield word.slice(0, frompos) +
word.slice(frompos + 1, topos) +
ch +
word.slice(topos);
}
}
for (let frompos = word.length; frompos > 0; frompos--) {
for (let topos = frompos - 1; topos > Math.max(0, frompos - C.MAX_CHAR_DISTANCE + 1); topos--) {
yield word.slice(0, topos) +
word[frompos] +
word.slice(topos, frompos) +
word.slice(frompos + 1);
}
}
}
/**
* Yields the permutations of a word where a character has been replaced by
* one of the characters found in the `TRY` string.
*
* @param word - The word to yield the permutations of.
* @param trystring - A string of characters which will be iterated through
* when replacing characters.
*/
export function* badchar(word, trystring) {
if (!trystring)
return;
for (const ch of trystring) {
for (let i = word.length; i > 0; i--) {
if (word[i] === ch)
continue;
yield word.slice(0, i) + ch + word.slice(i + 1);
}
}
}
/**
* Yields the permutations of a word where any repeated slice of two
* characters has been removed. e.g. `vacacation` to `vacation`.
*/
export function* doubletwochars(word) {
if (word.length < 5)
return;
for (let i = 2; i < word.length; i++) {
if (word[i - 2] === word[i] && word[i - 3] === word[i - 1]) {
yield word.slice(0, i - 1) + word.slice(i + 1);
}
}
}
/**
* Yields the permutations of a word where it has been split with a space
* in every position.
*/
export function* twowords(word) {
for (let i = 1; i < word.length; i++) {
yield [word.slice(0, i), word.slice(i)];
}
}
//# sourceMappingURL=permutations.js.map