UNPKG

deburr

Version:

Utility that simplifies substring search by normalizing character set. Diacritic marks and supplementary letters are converted to nearest ASCII character sequence before search.

91 lines (80 loc) 2.44 kB
// Characters considered to be invisible. export const DEBURR_DROP_RE = /[\u0300-\u036f\ufe20-\ufe23\ufeff]/g; // Mapping from UTF character to simplified character sequence. export const DEBURR = require('./deburr.json'); const CACHE = {}; export class Deburr { _chars = []; _offsets = []; _string = ''; constructor(value) { value = String(value); if (value in CACHE) { return CACHE[value]; } CACHE[value] = this; // Compute deburred characters and offset mapping for defined argument. let offset = 0; for (let i = 0; i < value.length; ++i) { let char = value.charAt(i); if (DEBURR_DROP_RE.test(char)) { char = ''; } else { char = DEBURR[char] || char; } this._chars[i] = char; this._offsets[i] = offset; offset += char.length; } this._string = this._chars.join(''); } toString() { return this._string; } lookup(value, index = 0) { let {_chars, _offsets} = this; if (value == null || _chars.length == 0) { return null; } let that = new Deburr(value); if (index >= _chars.length) { // Offset index exceeds total number of chars in string, so no matches would be found for sure. return null; } let i = this._string.indexOf(that._string, _offsets[index]); if (i < 0) { // Deburred content of strings did not match. return null; } let offset = _offsets.indexOf(i); if (offset < 0) { // Partial character matching occurred at beginning, ex. match second char in `ss` mapped to `ß`. return null; } for (var length = 0, count = 0; count < that._string.length; ++length) { count += _chars[offset + length].length; } if (count > that._string.length) { // Deburred string breaks last character. return null; } return {offset, length}; } lookupAll(value, index = 0, count = this._chars.length) { let ranges = []; while (count > 0) { let range = this.lookup(value, index); if (!range) { break; } ranges.push(range); index = range.offset + range.length; // If we matched zero-length substring force shift to next character to prevent infinite loop. if (range.length == 0) { index++; } count--; } return ranges; } }