UNPKG

@linkdotnet/stringoperations

Version:

Collection of string utilities. Edit-Distances, Search and Data structures. Offers for example trie, levenshtein distance.

131 lines (129 loc) 4.42 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Trie = void 0; class Trie { // eslint-disable-next-line no-useless-constructor constructor(ignoreCase = false) { this.ignoreCase = ignoreCase; this.children = {}; this.isLeaf = false; } /** * Adds a word to the trie * @param word Word to add to the trie */ addWord(word) { let current = this.children; for (let i = 0; i < word.length; i++) { const currentCharacter = this.ignoreCase ? word[i].toUpperCase() : word[i]; const node = this.createOrGetNode(currentCharacter, current); current = node.children; if (i === word.length - 1) { node.isLeaf = true; } } } /** * Check whether a word is contained in the trie * @param word Word to check whether it exists in the trie * @returns Returns true when the word is contained, otherwise false */ contains(word) { if (word.length === 0) { return false; } const node = this.findNode(word); return node !== undefined && node.isLeaf; } /** * Determines whether this trie starts with the specified character * @param text Character to compare * @returns True, when the text matches the beginning of the trie, otherwise false */ startsWith(text) { if (text.length === 0) { return false; } return this.findNode(text) !== undefined; } /** * Returns all words in the trie which starts with the given prefix * @param prefix Starting sequence which all returned words have to match * @returns All words in the trie which start with the given prefix */ getWordsWithPrefix(prefix) { const node = this.findNode(prefix); if (!node) { return []; } const results = []; const prefixes = this.stringToCharArray(prefix); this.collect(node, prefixes, results); return results; } /** * Deletes the key out of the trie. When multiple words matches this key all of them get deleted * @param key Word to delete * @remarks If trie contains out of 'Hello', 'Helsinki' and delete('Hel') is called, the trie is empty */ delete(key) { Trie.deleteInternal(this, key, 0); } createOrGetNode(character, children) { let node; if (children[character] !== undefined) { node = children[character]; } else { node = new Trie(this.ignoreCase); children[character] = node; } return node; } findNode(word) { let children = this.children; let currentNode; for (let i = 0; i < word.length; i++) { const currentCharacter = this.ignoreCase ? word[i].toUpperCase() : word[i]; if (children[currentCharacter] !== undefined) { currentNode = children[currentCharacter]; children = currentNode.children; } else { return undefined; } } return currentNode; } stringToCharArray(prefix) { const prefixes = []; for (let i = 0; i < prefix.length; i++) { prefixes.push(prefix[i]); } return prefixes; } collect(node, prefix, results) { if (Object.keys(node.children).length === 0) { results.push(prefix.join('')); return; } Object.keys(node.children).forEach(char => { prefix.push(char); this.collect(node.children[char], prefix, results); prefix.pop(); }); } static deleteInternal(node, word, index) { if (index === word.length) { node = null; } else { const char = word[index]; if ((node === null || node === void 0 ? void 0 : node.children[char]) && Trie.deleteInternal(node.children[char], word, index + 1)) { delete node.children[char]; } } return node === null || (node !== null && Object.keys(node.children).length === 0); } } exports.Trie = Trie;