业务实践篇3:中文搜索支持拼音首拼,全拼

905 阅读2分钟

中文搜索支持拼音首拼,全拼

本文主要内容: 基于pinyin库的实现中文搜索和标注匹配中的字符串。分别是从纯中文,拼音首拼,拼音全拼研究。

1.纯中文


纯中文比较好匹配,直接使用indexOf即可。代码如下:

if (escape(pinyinLetter).indexOf('%u') >= 0) {
  return {
    matchLen: pinyinLetter.length,
    index: text.indexOf(pinyinLetter),
  };
}

先判断是否为中文,如果为中文,直接使用indexOf匹配,返回index值和matchLen,matchLen为匹配中的长度,基于index和matchOf即可知道被匹配中的字符串。

2.拼音首拼


拼音首拼主要是提取出待匹配字段的每一个文字的拼音首字母,连接成字符串,然后直接使用IndexOf可以进行匹配。

 // 首字母
const ft = pinyin(text, {
  style: pinyin.STYLE_FIRST_LETTER, // 首字母
  // heteronym: true, // 启用多音字模式
  segment: true, // 启用分词,以解决多音字问题
}).join('');
// 
const ftIndex = ft.indexOf(pinyinLetter.toLowerCase())
return {
  matchLen: ftIndex > -1 ? pinyinLetter.length : 0,
  index: ftIndex,
};

3.拼音全拼


这是本文的重点内容,处理拼音全拼难点在于匹配中的字段长度。举个例子,“xian”的匹配可以是多种,例如“现”,“西安”,“夏娜”等等。

本文主要采用的是使用匹配中的字段的拼音长度反向计算匹配中的长度。比如,“现”的拼音为“xian”,即匹配中长度为1,“西安”的拼音为“xi,an”,先匹配“xi”与“xi”,后匹配“an”和“an”,即匹配中长度为2,“夏娜”主要是最后一个字是非完整全拼的匹配,“夏娜”的拼音为“xia,na”,先匹配“xia”,在匹配“n”与“na”,可计算出匹配长度为2。
代码如下:

// 全拼
    const al = pinyin(text, {
        style: pinyin.STYLE_NORMAL, // 普通风格,即不带声调。
    });
    let beginIndex = al.join('').indexOf(pinyinLetter.toLowerCase());
    let num = 0;
    let tIndex = 0;
    if (beginIndex > -1) {
        let plen = pinyinLetter.length;
        let wordLen = 0;

        for (let i = 0; i < al.length; i++) {
            // 查询从第几个文字开始匹配
            if (beginIndex === 0) {
                tIndex = 0;
                break;
            } else {
                wordLen += al[i][0].length;
                if (wordLen === beginIndex) {
                    tIndex = i + 1;
                    break;
                } else if (wordLen > beginIndex) {
                    // 未从汉字拼音首字母开始匹配,即认为没有匹配中
                    tIndex = al.length;
                    break;
                }
            }
        }

        for (let i = tIndex; i < al.length; i++) {
            // 计算匹配中汉字的长度
            plen -= al[i][0].length;
            num++;
            if (plen <= 0) {
                break;
            }
        }
    }
    if (num > 0) {
        return {
            matchLen: num,
            index: tIndex,
        }
    }

4.实例演示

纯中文搜索:
中文.gif
拼音首拼
首拼.gif
拼音全拼
全拼.gif