diff --git a/src/components/SearchBoxFlexSearch.vue b/src/components/SearchBoxFlexSearch.vue index 013bee1..dceaa08 100644 --- a/src/components/SearchBoxFlexSearch.vue +++ b/src/components/SearchBoxFlexSearch.vue @@ -51,6 +51,7 @@ import { Document } from 'flexsearch' import data from '@dynamic/vuepress-plugin-flexsearch/data' import excerpt from './excerpt' +import matcher from './matcher'; import ngram from '../tokenizer/ngram' /* global FLEX_SEARCH_HOTKEYS */ @@ -159,6 +160,7 @@ export default { setUpFlexSearchDocument () { for (const locale in data) { const doc = new Document({ + matcher: matcher, tokenize: 'forward', id: 'key', index: [ diff --git a/src/components/excerpt.js b/src/components/excerpt.js index b6c6945..a1c9e2b 100644 --- a/src/components/excerpt.js +++ b/src/components/excerpt.js @@ -1,11 +1,13 @@ const ExcerptHtml = require('./excerpt-html'); const TextProcessing = require('./text-processing'); +const matcher = require('./matcher'); + /** * @typedef {Object} ExcerptOption * @property {number} [aroundLength] - * @property {string} [head] - * @property {string} [tail] + * @property {string} [headText] + * @property {string} [tailText] */ /** @@ -22,7 +24,7 @@ const create = (content, query, option) => { } = option || {}; const contentLowerCase = content.toLowerCase(); - const queryLowerCase = query.toLowerCase(); + const queryLowerCase = addMatcher(query).toLowerCase(); const textProcessing = new TextProcessing(); @@ -46,6 +48,22 @@ const create = (content, query, option) => { return content.slice(0, aroundLength) + (content.length > aroundLength ? tailText : ''); }; +/** + * @param {string} query + * @return {string} + */ +const addMatcher = (query) => { + let converted1 = query; + let converted2 = query; + + Object.keys(matcher).forEach((key) => { + converted1 = converted1.replaceAll(key, matcher[key]); + converted2 = converted2.replaceAll(matcher[key], key); + }) + + return [query, converted1, converted2].join(' '); +}; + /** * @param {string} excerpt * @param {string[]} queries diff --git a/src/components/matcher.js b/src/components/matcher.js new file mode 100644 index 0000000..d2ac349 --- /dev/null +++ b/src/components/matcher.js @@ -0,0 +1,95 @@ +module.exports = { + '1': '1', + '2': '2', + '3': '3', + '4': '4', + '5': '5', + '6': '6', + '7': '7', + '8': '8', + '9': '9', + '0': '0', + + 'あ': 'ア', + 'い': 'イ', + 'う': 'ウ', + 'え': 'エ', + 'お': 'オ', + 'か': 'カ', + 'き': 'キ', + 'く': 'ク', + 'け': 'ケ', + 'こ': 'コ', + 'さ': 'サ', + 'し': 'シ', + 'す': 'ス', + 'せ': 'セ', + 'そ': 'ソ', + 'た': 'タ', + 'ち': 'チ', + 'つ': 'ツ', + 'て': 'テ', + 'と': 'ト', + 'な': 'ナ', + 'に': 'ニ', + 'ぬ': 'ヌ', + 'ね': 'ネ', + 'の': 'ノ', + 'は': 'ハ', + 'ひ': 'ヒ', + 'ふ': 'フ', + 'へ': 'ヘ', + 'ほ': 'ホ', + 'ま': 'マ', + 'み': 'ミ', + 'む': 'ム', + 'め': 'メ', + 'も': 'モ', + 'や': 'ヤ', + 'ゆ': 'ユ', + 'よ': 'ヨ', + 'ら': 'ラ', + 'り': 'リ', + 'る': 'ル', + 'れ': 'レ', + 'ろ': 'ロ', + 'わ': 'ワ', + 'を': 'ヲ', + 'ん': 'ン', + + 'が': 'ガ', + 'ぎ': 'ギ', + 'ぐ': 'グ', + 'げ': 'ゲ', + 'ご': 'ゴ', + 'ざ': 'ザ', + 'じ': 'ジ', + 'ず': 'ズ', + 'ぜ': 'ゼ', + 'ぞ': 'ゾ', + 'だ': 'ダ', + 'ぢ': 'ヂ', + 'づ': 'ヅ', + 'で': 'デ', + 'ど': 'ド', + 'ば': 'バ', + 'び': 'ビ', + 'ぶ': 'ブ', + 'べ': 'ベ', + 'ぼ': 'ボ', + + 'ぱ': 'パ', + 'ぴ': 'ピ', + 'ぷ': 'プ', + 'ぺ': 'ペ', + 'ぽ': 'ポ', + + 'ぁ': 'ァ', + 'ぃ': 'ィ', + 'ぅ': 'ゥ', + 'ぇ': 'ェ', + 'ぉ': 'ォ', + 'ゃ': 'ャ', + 'ゅ': 'ュ', + 'ょ': 'ョ', +}; diff --git a/test/components/excerpt.js b/test/components/excerpt.js index 9505dce..7a967ae 100644 --- a/test/components/excerpt.js +++ b/test/components/excerpt.js @@ -84,6 +84,25 @@ describe('components', () => { 'weigh ...', ], + // matcher + [ + '2023', + {}, + '2023年', + '2023年', + ], + [ + '2023', + {}, + '2023年', + '2023年', + ], + [ + 'いぬ ねこ', + {}, + 'イヌとネコ', + 'イヌネコ', + ], ]; dataSet.forEach(([query, option, content, highlighted]) => {