@pnfo/singlish-search
Version:
search Sinhala text using Singlish letters
230 lines (214 loc) • 10.6 kB
JavaScript
// sinhala unicode -> easy singlish
export const singlish_vowels = [
['අ', 'a'],
['ආ', 'aa'],
['ඇ', 'ae'],
['ඈ', 'ae, aee'],
['ඉ', 'i'],
['ඊ', 'ii'],
['උ', 'u'],
['ඌ', 'uu'],
['එ', 'e'],
['ඒ', 'ee'],
['ඔ', 'o'],
['ඕ', 'oo'],
['ඓ', 'ai'], // sinhala only begin
['ඖ', 'ou'],
['ඍ', 'ru'],
['ඎ', 'ru, ruu'],
//['ඏ', 'li'], /** 2020-6-22 commented out some rare letters to prevent too many possibilites */
//['ඐ', 'li, lii'] // sinhala only end
]
export const singlish_specials = [
['ඞ්', 'n'],
['ං', 'n'],
//['ඃ', 'n, m'] // sinhala only
]
export const singlish_consonants = [
['ක', 'k'],
['ග', 'g'],
['ච', 'c, ch'],
['ජ', 'j'],
['ට', 't'],
['ඩ', 'd'],
['ණ', 'n'],
['ත', 'th'],
['ද', 'd'],
['න', 'n'],
['ප', 'p'],
['බ', 'b'],
['ම', 'm'],
['ය', 'y'],
['ර', 'r'],
['ල', 'l'],
['ව', 'v, w'],
['ශ', 'sh'],
['ෂ', 'sh'],
['ස', 's'],
['හ', 'h'],
['ළ', 'l'],
['ෆ', 'f'],
['ඛ', 'kh, k'],
['ඤ', 'kn'],
['ඨ', 't'],
['ඝ', 'gh'],
['ඟ', 'ng'],
['ඡ', 'ch'],
['ඣ', 'jh'],
['ඦ', 'nj'],
['ඪ', 'dh'],
['ඬ', 'nd'],
['ථ', 'th'],
['ධ', 'dh'],
['ඳ', 'nd'],
['ඵ', 'ph'],
['භ', 'bh'],
['ඹ', 'mb'],
['ඥ', 'gn'] // sinhala only
]
// sinh before, sinh after, roman after
export const singlish_combinations = [
['්', ''], //ක්
['', 'a'], //ක
['ා', 'a, aa'], //කා
['ැ', 'ae'],
['ෑ', 'aee'],
['ි', 'i'],
['ී', 'ii'],
['ු', 'u'],
['ූ', 'uu'],
['ෙ', 'e'],
['ේ', 'ee'],
['ෛ', 'ei'],
['ො', 'o'],
['ෝ', 'oo'],
['්ර', 'ra'], //ක්ර
['්රා', 'ra, raa'], //ක්රා
['්රැ', 'rae'],
['්රෑ', 'rae, raee'],
['්රි', 'ri'],
['්රී', 'ri, rii'],
['්රෙ', 're'],
['්රේ', 're, ree'],
['්රෛ', 'rei'],
['්රො', 'ro'],
['්රෝ', 'ro, roo'],
['්ය', 'ya'], //ක්ය
['්යා', 'ya, yaa'], //ක්යා
['්යැ', 'yae'],
['්යෑ', 'yae, yaee'],
['්යි', 'yi'],
['්යී', 'yi, yii'],
['්යු', 'yu'],
['්යූ', 'yu, yuu'],
['්යෙ', 'ye'],
['්යේ', 'ye, yee'],
['්යෛ', 'yei'],
['්යො', 'yo'],
['්යෝ', 'yo, yoo'],
['ෘ', 'ru'], // sinhala only begin
['ෲ', 'ru, ruu'],
['ෞ', 'au'],
//['ෟ', 'li'],
//['ෳ', 'li, lii'] // sinhala only end
]
const singlishMapping = {}
let maxSinglishKeyLen = 0
function addToSinglishMapping(values, pSinhStr, pRomanStr) {
values.forEach(pair => {
const sinh = pair[0] + pSinhStr
const romans = pair[1].split(',');
const pRomans = pRomanStr.split(',');
romans.forEach(roman => {
pRomans.forEach(pRoman => {
const mapIndex = roman.trim() + pRoman.trim()
if (mapIndex in singlishMapping) {
singlishMapping[mapIndex].push(sinh)
} else {
singlishMapping[mapIndex] = [sinh]
maxSinglishKeyLen = Math.max(mapIndex.length, maxSinglishKeyLen)
}
})
})
})
}
addToSinglishMapping(singlish_vowels, '', '')
addToSinglishMapping(singlish_specials, '', '')
singlish_combinations.forEach(combi => {
addToSinglishMapping(singlish_consonants, combi[0], combi[1]);
})
console.log(`singlish map initialized. maxSinglishKeyLen: ${maxSinglishKeyLen}`)
const maxInputLength = 20 // prevent call stack exceeding the stack size
export function getPossibleMatches(input) {
if (input.length > maxInputLength) return [input]
let matches = []
for (let len = 1; len <= maxSinglishKeyLen && len <= input.length; len++) {
const prefix = input.slice(0, len)
const rest = input.slice(len)
matches.push(...(permuteMatches(prefix, rest)))
}
// reduce the number of matches to prevent sql query from exploding
// 1) hal followed by හ් (occur by mis identification of kh, th, bh etc for double hals)
// 2) consecutive independent vowels
// 3) hal/n followed by a indept vowel
// that do not occur in sinhala
matches = matches.filter(match => !(/[ක-ෆ]්හ්|[අ-ඎ][අ-ඎ]|[්ං][අ-ඎ]/.test(match)) )
// further remove rare consonants to make the matches usable at least partially
if (matches.length > 500) {
matches = matches.filter(match => !/[ඤඨඟඡඣඦඪඬඳඵඥ]/.test(match))
}
return matches
}
function permuteMatches(prefix, rest) {
// if prefix is all sinhala then pass through the prefix - this allows sinhala and singlish mixing and ending dot
const prefixMappings = isSinglishQuery(prefix) ? singlishMapping[prefix] : (prefix.length == 1 ? [prefix] : [])
if (!prefixMappings) { // recursion ending condition
return []
}
if (!rest.length) { // recursion ending condition
return prefixMappings
}
const restMappings = getPossibleMatches(rest);
const fullMappings = []
restMappings.forEach(restM =>
prefixMappings.forEach(prefixM =>
fullMappings.push(prefixM + restM)
)
)
return fullMappings
}
export function isSinglishQuery(query) {
return /[A-Za-z]/.test(query);
}
/*
[
'ස්හස්ත්රය', 'ස්හාස්ත්රය', 'ස්හස්ථ්රය', 'ස්හාස්ථ්රය',
'ස්හස්ත්රාය', 'ස්හාස්ත්රාය', 'ස්හස්ථ්රාය', 'ස්හාස්ථ්රාය',
'ස්හස්ත්රයා', 'ස්හාස්ත්රයා', 'ස්හස්ථ්රයා', 'ස්හාස්ථ්රයා',
'ස්හස්ත්රායා', 'ස්හාස්ත්රායා', 'ස්හස්ථ්රායා', 'ස්හාස්ථ්රායා',
'ශස්ත්රය', 'ෂස්ත්රය', 'ශාස්ත්රය', 'ෂාස්ත්රය',
'ශස්ථ්රය', 'ෂස්ථ්රය', 'ශාස්ථ්රය', 'ෂාස්ථ්රය',
'ශස්ත්රාය', 'ෂස්ත්රාය', 'ශාස්ත්රාය', 'ෂාස්ත්රාය',
'ශස්ථ්රාය', 'ෂස්ථ්රාය', 'ශාස්ථ්රාය', 'ෂාස්ථ්රාය',
'ශස්ත්රයා', 'ෂස්ත්රයා', 'ශාස්ත්රයා', 'ෂාස්ත්රයා',
'ශස්ථ්රයා', 'ෂස්ථ්රයා', 'ශාස්ථ්රයා', 'ෂාස්ථ්රයා',
'ශස්ත්රායා', 'ෂස්ත්රායා', 'ශාස්ත්රායා', 'ෂාස්ත්රායා',
'ශස්ථ්රායා', 'ෂස්ථ්රායා', 'ශාස්ථ්රායා', 'ෂාස්ථ්රායා'
]
'ජණඩ්හිපට්හිවරණය', 'ජාණඩ්හිපට්හිවරණය', 'ජනඩ්හිපට්හිවරණය', 'ජානඩ්හිපට්හිවරණය',
'ජණාඩ්හිපට්හිවරණය', 'ජාණාඩ්හිපට්හිවරණය', 'ජනාඩ්හිපට්හිවරණය', 'ජානාඩ්හිපට්හිවරණය',
'ජණද්හිපට්හිවරණය', 'ජාණද්හිපට්හිවරණය', 'ජනද්හිපට්හිවරණය', 'ජානද්හිපට්හිවරණය',
'ජණාද්හිපට්හිවරණය', 'ජාණාද්හිපට්හිවරණය', 'ජනාද්හිපට්හිවරණය', 'ජානාද්හිපට්හිවරණය',
'ජණඩ්හිපාට්හිවරණය', 'ජාණඩ්හිපාට්හිවරණය', 'ජනඩ්හිපාට්හිවරණය', 'ජානඩ්හිපාට්හිවරණය',
'ජණාඩ්හිපාට්හිවරණය', 'ජාණාඩ්හිපාට්හිවරණය', 'ජනාඩ්හිපාට්හිවරණය', 'ජානාඩ්හිපාට්හිවරණය',
'ජණද්හිපාට්හිවරණය', 'ජාණද්හිපාට්හිවරණය', 'ජනද්හිපාට්හිවරණය', 'ජානද්හිපාට්හිවරණය',
'ජණාද්හිපාට්හිවරණය', 'ජාණාද්හිපාට්හිවරණය', 'ජනාද්හිපාට්හිවරණය', 'ජානාද්හිපාට්හිවරණය',
'ජණඩ්හිපට්හිවාරණය', 'ජාණඩ්හිපට්හිවාරණය', 'ජනඩ්හිපට්හිවාරණය', 'ජානඩ්හිපට්හිවාරණය',
'ජණාඩ්හිපට්හිවාරණය', 'ජාණාඩ්හිපට්හිවාරණය', 'ජනාඩ්හිපට්හිවාරණය', 'ජානාඩ්හිපට්හිවාරණය',
'ජණද්හිපට්හිවාරණය', 'ජාණද්හිපට්හිවාරණය', 'ජනද්හිපට්හිවාරණය', 'ජානද්හිපට්හිවාරණය',
'ජණාද්හිපට්හිවාරණය', 'ජාණාද්හිපට්හිවාරණය', 'ජනාද්හිපට්හිවාරණය', 'ජානාද්හිපට්හිවාරණය',
'ජණඩ්හිපාට්හිවාරණය', 'ජාණඩ්හිපාට්හිවාරණය', 'ජනඩ්හිපාට්හිවාරණය', 'ජානඩ්හිපාට්හිවාරණය',
'ජණාඩ්හිපාට්හිවාරණය', 'ජාණාඩ්හිපාට්හිවාරණය', 'ජනාඩ්හිපාට්හිවාරණය', 'ජානාඩ්හිපාට්හිවාරණය',
'ජණද්හිපාට්හිවාරණය', 'ජාණද්හිපාට්හිවාරණය', 'ජනද්හිපාට්හිවාරණය', 'ජානද්හිපාට්හිවාරණය',
'ජණාද්හිපාට්හිවාරණය', 'ජාණාද්හිපාට්හිවාරණය', 'ජනාද්හිපාට්හිවාරණය', 'ජානාද්හිපාට්හිවාරණය',
*/