321 lines
6.3 KiB
JavaScript
321 lines
6.3 KiB
JavaScript
|
import { IndexInterface } from "./type.js";
|
||
|
import { create_object, get_keys } from "./common.js";
|
||
|
|
||
|
/**
|
||
|
* @param {!string} str
|
||
|
* @param {boolean|Array<string|RegExp>=} normalize
|
||
|
* @param {boolean|string|RegExp=} split
|
||
|
* @param {boolean=} _collapse
|
||
|
* @returns {string|Array<string>}
|
||
|
* @this IndexInterface
|
||
|
*/
|
||
|
|
||
|
export function pipeline(str, normalize, split, _collapse) {
|
||
|
|
||
|
if (str) {
|
||
|
|
||
|
if (normalize) {
|
||
|
|
||
|
str = replace(str, /** @type {Array<string|RegExp>} */normalize);
|
||
|
}
|
||
|
|
||
|
if (this.matcher) {
|
||
|
|
||
|
str = replace(str, this.matcher);
|
||
|
}
|
||
|
|
||
|
if (this.stemmer && 1 < str.length) {
|
||
|
|
||
|
str = replace(str, this.stemmer);
|
||
|
}
|
||
|
|
||
|
if (_collapse && 1 < str.length) {
|
||
|
|
||
|
str = collapse(str);
|
||
|
}
|
||
|
|
||
|
if (split || "" === split) {
|
||
|
|
||
|
const words = str.split( /** @type {string|RegExp} */split);
|
||
|
|
||
|
return this.filter ? filter(words, this.filter) : words;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
// TODO improve normalize + remove non-delimited chars like in "I'm" + split on whitespace+
|
||
|
|
||
|
export const regex_whitespace = /[\p{Z}\p{S}\p{P}\p{C}]+/u;
|
||
|
// https://github.com/nextapps-de/flexsearch/pull/414
|
||
|
//export const regex_whitespace = /[\s\xA0\u2000-\u200B\u2028\u2029\u3000\ufeff!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~]/
|
||
|
const regex_normalize = /[\u0300-\u036f]/g;
|
||
|
|
||
|
export function normalize(str) {
|
||
|
|
||
|
if (str.normalize) {
|
||
|
|
||
|
str = str.normalize("NFD").replace(regex_normalize, "");
|
||
|
}
|
||
|
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {!string} str
|
||
|
* @param {boolean|Array<string|RegExp>=} normalize
|
||
|
* @param {boolean|string|RegExp=} split
|
||
|
* @param {boolean=} _collapse
|
||
|
* @returns {string|Array<string>}
|
||
|
*/
|
||
|
|
||
|
// FlexSearch.prototype.pipeline = function(str, normalize, split, _collapse){
|
||
|
//
|
||
|
// if(str){
|
||
|
//
|
||
|
// if(normalize && str){
|
||
|
//
|
||
|
// str = replace(str, /** @type {Array<string|RegExp>} */ (normalize));
|
||
|
// }
|
||
|
//
|
||
|
// if(str && this.matcher){
|
||
|
//
|
||
|
// str = replace(str, this.matcher);
|
||
|
// }
|
||
|
//
|
||
|
// if(this.stemmer && str.length > 1){
|
||
|
//
|
||
|
// str = replace(str, this.stemmer);
|
||
|
// }
|
||
|
//
|
||
|
// if(_collapse && str.length > 1){
|
||
|
//
|
||
|
// str = collapse(str);
|
||
|
// }
|
||
|
//
|
||
|
// if(str){
|
||
|
//
|
||
|
// if(split || (split === "")){
|
||
|
//
|
||
|
// const words = str.split(/** @type {string|RegExp} */ (split));
|
||
|
//
|
||
|
// return this.filter ? filter(words, this.filter) : words;
|
||
|
// }
|
||
|
// }
|
||
|
// }
|
||
|
//
|
||
|
// return str;
|
||
|
// };
|
||
|
|
||
|
// export function pipeline(str, normalize, matcher, stemmer, split, _filter, _collapse){
|
||
|
//
|
||
|
// if(str){
|
||
|
//
|
||
|
// if(normalize && str){
|
||
|
//
|
||
|
// str = replace(str, normalize);
|
||
|
// }
|
||
|
//
|
||
|
// if(matcher && str){
|
||
|
//
|
||
|
// str = replace(str, matcher);
|
||
|
// }
|
||
|
//
|
||
|
// if(stemmer && str.length > 1){
|
||
|
//
|
||
|
// str = replace(str, stemmer);
|
||
|
// }
|
||
|
//
|
||
|
// if(_collapse && str.length > 1){
|
||
|
//
|
||
|
// str = collapse(str);
|
||
|
// }
|
||
|
//
|
||
|
// if(str){
|
||
|
//
|
||
|
// if(split !== false){
|
||
|
//
|
||
|
// str = str.split(split);
|
||
|
//
|
||
|
// if(_filter){
|
||
|
//
|
||
|
// str = filter(str, _filter);
|
||
|
// }
|
||
|
// }
|
||
|
// }
|
||
|
// }
|
||
|
//
|
||
|
// return str;
|
||
|
// }
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @param {Array<string>} words
|
||
|
* @returns {Object<string, string>}
|
||
|
*/
|
||
|
|
||
|
export function init_filter(words) {
|
||
|
|
||
|
const filter = create_object();
|
||
|
|
||
|
for (let i = 0, length = words.length; i < length; i++) {
|
||
|
|
||
|
filter[words[i]] = 1;
|
||
|
}
|
||
|
|
||
|
return filter;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {!Object<string, string>} obj
|
||
|
* @param {boolean} is_stemmer
|
||
|
* @returns {Array}
|
||
|
*/
|
||
|
|
||
|
export function init_stemmer_or_matcher(obj, is_stemmer) {
|
||
|
const keys = get_keys(obj),
|
||
|
length = keys.length,
|
||
|
final = [];
|
||
|
|
||
|
|
||
|
let removal = "",
|
||
|
count = 0;
|
||
|
|
||
|
for (let i = 0, key, tmp; i < length; i++) {
|
||
|
|
||
|
key = keys[i];
|
||
|
tmp = obj[key];
|
||
|
|
||
|
if (tmp) {
|
||
|
|
||
|
final[count++] = regex(is_stemmer ? "(?!\\b)" + key + "(\\b|_)" : key);
|
||
|
final[count++] = tmp;
|
||
|
} else {
|
||
|
|
||
|
removal += (removal ? "|" : "") + key;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (removal) {
|
||
|
|
||
|
final[count++] = regex(is_stemmer ? "(?!\\b)(" + removal + ")(\\b|_)" : "(" + removal + ")");
|
||
|
final[count] = "";
|
||
|
}
|
||
|
|
||
|
return final;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {!string} str
|
||
|
* @param {Array} regexp
|
||
|
* @returns {string}
|
||
|
*/
|
||
|
|
||
|
export function replace(str, regexp) {
|
||
|
|
||
|
for (let i = 0, len = regexp.length; i < len; i += 2) {
|
||
|
|
||
|
str = str.replace(regexp[i], regexp[i + 1]);
|
||
|
|
||
|
if (!str) {
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {!string} str
|
||
|
* @returns {RegExp}
|
||
|
*/
|
||
|
|
||
|
export function regex(str) {
|
||
|
|
||
|
return new RegExp(str, "g");
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Regex: replace(/(?:(\w)(?:\1)*)/g, "$1")
|
||
|
* @param {!string} string
|
||
|
* @returns {string}
|
||
|
*/
|
||
|
|
||
|
export function collapse(string) {
|
||
|
|
||
|
let final = "",
|
||
|
prev = "";
|
||
|
|
||
|
for (let i = 0, len = string.length, char; i < len; i++) {
|
||
|
|
||
|
if ((char = string[i]) !== prev) {
|
||
|
|
||
|
final += prev = char;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return final;
|
||
|
}
|
||
|
|
||
|
// TODO using fast-swap
|
||
|
export function filter(words, map) {
|
||
|
const length = words.length,
|
||
|
filtered = [];
|
||
|
|
||
|
|
||
|
for (let i = 0, count = 0; i < length; i++) {
|
||
|
|
||
|
const word = words[i];
|
||
|
|
||
|
if (word && !map[word]) {
|
||
|
|
||
|
filtered[count++] = word;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return filtered;
|
||
|
}
|
||
|
|
||
|
// const chars = {a:1, e:1, i:1, o:1, u:1, y:1};
|
||
|
//
|
||
|
// function collapse_repeating_chars(string){
|
||
|
//
|
||
|
// let collapsed_string = "",
|
||
|
// char_prev = "",
|
||
|
// char_next = "";
|
||
|
//
|
||
|
// for(let i = 0; i < string.length; i++){
|
||
|
//
|
||
|
// const char = string[i];
|
||
|
//
|
||
|
// if(char !== char_prev){
|
||
|
//
|
||
|
// if(i && (char === "h")){
|
||
|
//
|
||
|
// if((chars[char_prev] && chars[char_next]) || (char_prev === " ")){
|
||
|
//
|
||
|
// collapsed_string += char;
|
||
|
// }
|
||
|
// }
|
||
|
// else{
|
||
|
//
|
||
|
// collapsed_string += char;
|
||
|
// }
|
||
|
// }
|
||
|
//
|
||
|
// char_next = (
|
||
|
//
|
||
|
// (i === (string.length - 1)) ?
|
||
|
//
|
||
|
// ""
|
||
|
// :
|
||
|
// string[i + 1]
|
||
|
// );
|
||
|
//
|
||
|
// char_prev = char;
|
||
|
// }
|
||
|
//
|
||
|
// return collapsed_string;
|
||
|
// }
|