拼音分词与输入距离总结

总结下拼音搜索的常见做法。

主要功能:
基于字典分词。
尽量消除歧义词避免分错。
忽略单个拼音,原业务单个拼音可以当做简拼处理。
判断一个字符串是否是拼音,’aaao’ 不认为是拼音,原因是忽略单个拼音。(可修正,在判断长度上>1去掉)

分析:
yuegaofenghei =>最短分词会忽略 e
youerjizhen=>最长会忽略er。
基于上面两种情况,进行merge,取交集合并。
便会得到正确的分词。

输入距离算法:
输入距离,不单单是一种编辑距离,也不是相似性。
例如:

糖尿病 =>与糖尿尿病
编辑距离与汉明距离都认为只差一个(汉明距离是hash化,局部敏感这里只是说明业务原理)

余弦相似,无法判断,因为这只是一个词,无法算距离。
事实上:糖尿病肾病,应该是预期提示,而 ‘糖x尿x病’ 无论x在哪都不应该排序在前。(本业务忽略这个情况,只是简单处理,建议加权差字数字为2 up n(字数)。)
算法实现原理,定义期望因子为2,即:期望前驱出现优先,后驱,加快减少。
简单根据指数,对数原理,进行log化,与指数化加权。

实现效果,满足业务需求,而且极大的方便了输入排序。
Hacknews:
热度排序(略)设因子为1.8 ,即:过一天的衰减率为100-1,若要减缓减少重力因子即可,具体需要概率算法。

代码:
package com.hm.apollo.framework.utils;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**

  • Created by ant_shake_tree on 16/3/28.
    /
    public class Utils {
    private Utils cons = new Utils();
    public static String replaceBlank(String str) {
    String dest = "";
    if (str != null) {
    Pattern p = Pattern.compile("\s+|\t|\r|\n|\+|-|&|\||!|\(|\)|\{|\}|\[|\]|"|~|\
    |\?|\^");
    Matcher m = p.matcher(str);
    dest = m.replaceAll("");
    }
    //+ - && || ! ( ) { } [ ] ^ " ~ * ? :
    return dest;
    }
    // public static void main(String[] args){
    // System.out.println(Utils.replaceBlank("撒地方sad^fa \t +-&&|!(){}[]" " +
    // "ssa ~fas*?dfdf"));
    // }
/**
 * 修改敏感字符编码
 *
 * @param value
 * @return
 */
public static String queryEncode(String value) {
    String re[][] = {{"\\(", "\\\\\\\\\\("},
            {"\\)", "\\\\\\);"},
            {"-", "\\-"}
    };
    for (int i = 0; i < re.length; i++) {
        value = value.replaceAll(re[i][0], re[i][1]);
    }
    return value;
}
/**
 * 验证汉字为true
 *
 * @param s
 * @return
 */
public static boolean isLetterorDigit(String s) {
    if (s.equals("") || s == null) {
        return false;
    }
    for (int i = 0; i < s.length(); i++) {
        if (!Character.isLetterOrDigit(s.charAt(i))) {
            // if (!Character.isLetter(s.charAt(i))){
            return false;
        }
    }
    // Character.isJavaLetter()
    return true;
}
/**
 * 马晓超
 * 如果前驱匹配log函数
 * 后驱匹配长度差
 * 乱序 指数匹配
 *
 * @param base
 * @param str2
 * @return
 */
public static double shuruDistance(String base, String str2) {
    if (base.equals(str2)) return 0;
    if (str2.contains(base) && str2.startsWith(base)) {
        return Math.max(Math.log(Math.abs(base.length() - str2.length())), 0.5);
    }
    if (str2.contains(base)) {
        return Math.abs(base.length() - str2.length());
    }
    return Math.pow(2, Math.abs(base.length() - str2.length()));
}
public static List<String> merge(List<String> list) {
    List<String> cp = new ArrayList<>(list);
    for (int i = 0; i < list.size(); i++) {
        for (int j = i + 1; j < list.size(); j++) {
            if (list.get(i).length() >= list.get(j).length()) {
                if (list.get(i).contains(list.get(j))) {
                    cp.remove(list.get(j));
                }
            } else {
                if (list.get(j).contains(list.get(i))) {
                    cp.remove(list.get(i));
                }
            }
        }
    }
    return cp;
}
public static void main(String[] args) {
    List<String> getp = getPinyin("aaao");
    System.out.println(isPinyin("youerjiz"));
    System.out.println(isPinyin("aaao"));
    System.out.println(isPinyin("youerjiz"));
    System.out.println(isPinyin("youerjiz"));
}
/**
 * 分词,全组合分词
 */
public static List<String> fullAssembly(String sentense) {
    List<String> stringArrayList = new ArrayList<>();
    for (int beginIndex = 0; beginIndex < sentense.length(); beginIndex++) {
        for (int endIndex = beginIndex + 1; endIndex <= sentense.length(); endIndex++) {
            String kws = sentense.substring(beginIndex, endIndex);
            if ((endIndex - beginIndex) == 1) continue;
            if (getPinyinMap().containsKey(kws)) {
                stringArrayList.add(kws);
            } else {
                stringArrayList.add(kws);
            }
        }
    }
    return stringArrayList;
}
/***
 * 拼音分词
 */
public static List<String> getPinyin(String pinyin) {
    if (!isAlpha(pinyin)) return Lists.newArrayList();
    if (pinyin.length() < 2) return Lists.newArrayList();
    final List<String> longp = Lists.newArrayList();
    final List<String> storp = Lists.newArrayList();
    int len = 0;
    int longlen = 0;
    for (int i = 0; i < pinyin.length(); i++) {
        StringBuffer str = new StringBuffer();
        int j = i;
        for (; j < pinyin.length(); j++) {
            if (!isAlphaChar(pinyin.charAt(j))) {
                continue;
            }
            str.append(pinyin.charAt(j));
            if (str.length() > 1 && getPinyinMap().containsKey(str.toString())) {
                len += str.length();
                storp.add(str.toString());
                i = j;
                break;
            }
        }
    }
    int index = 0;
    int jiequ = 0;
    //最大切分
    for (int i = 0; i < pinyin.length(); i++) {
        StringBuffer str = new StringBuffer();
        for (int j = i; j < pinyin.length(); j++) {
            if (!isAlphaChar(pinyin.charAt(j))) {
                continue;
            }
            str.append(pinyin.charAt(j));
            index++;
            if (str.length() > 1 && getPinyinMap().containsKey(str.toString())) {
                i = j;
                jiequ = index;
                if (j == pinyin.length() - 1) {
                    if (!"".equals(str.toString())) {
                        longp.add(str.toString());
                        longlen += str.length();
                    }
                    break;
                }
            }
            if ((str.length() >= 5 && !getPinyinMap().containsKey(str.toString())) || (j == pinyin.length() - 1)) {
                String sub=str.toString().substring(0, jiequ);
                if (!"".equals(sub)) {
                    longp.add(sub);
                    longlen += sub.length();
                }
                index = 0;
                jiequ = 0;
                break;
            }
        }
    }
    if(storp.size()==0||longp.size()==0)return storp;
    if (longlen == pinyin.length()) {
        return longp.stream().filter(s -> StringUtils.isNotEmpty(s)).collect(Collectors.toList());
    } else if (len < pinyin.length()) {
        mergePinyinList(storp,longp,len,pinyin.length());
        return storp.stream().filter(s -> StringUtils.isNotEmpty(s)).collect(Collectors.toList());
    }
    return longp.stream().filter(s -> StringUtils.isNotEmpty(s)).collect(Collectors.toList());
}
public static boolean isAlpha(String charSequence) {
    if (charSequence == null) return false;
    for (char c : charSequence.toCharArray()) {
        if (c == '-') continue;
        if (!isAlphaChar(c)) {
            return false;
        }
    }
    return true;
}
public static boolean isAlphaChar(char c) {
    if (((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) return true;
    else return false;
}
/**
 * 判断是否是拼音
 *
 * @param keyworld
 * @return
 */
public static boolean isPinyin(String keyworld) {
    if (keyworld.length() <= 2) {
        return false;
    }
    List<String> list = getPinyin(keyworld);
    if (list.size() > 0) {
        int len = 0;
        for (String k : list) {
            len += k.length();
        }
        if (len == keyworld.length()) {
            return true;
        }
        //排除错误
        if ((keyworld.length() - len) == 1 && keyworld.startsWith(list.get(0))) return true;
    }
    return false;
}
private static void mergePinyinList(List<String> shortPinyin,List<String> longPinyin,int lenS,int len){
    if(lenS<len){
        for(int i=shortPinyin.size()-1;i>=0;i--){
            String shortStr=shortPinyin.get(i);
            for(int j=longPinyin.size()-1;j>=0;j--) {
                String s = longPinyin.get(j);
                if (s.contains(shortStr)) {
                    lenS+=s.length()-shortStr.length();
                    shortPinyin.remove(shortStr);
                    shortPinyin.add(i,s);
                    longPinyin.remove(s);
                }
                if(lenS>=len)
                    break;
            }
        }
    }
}
private static final Map<String, Integer> stringIntegerMap = Stream.of("a", "ai", "an", "ang", "ao", "ba", "bai",
        "ban", "bang", "bao", "bei", "ben", "beng", "bi", "bian", "biao", "bie", "bin", "bing", "bo", "bu", "ca",
        "cai", "can", "cang", "cao", "ce", "cen", "ceng", "cha", "chai", "chan", "chang", "chao", "che", "chen",
        "cheng", "chi", "chong", "chou", "chu", "chua", "chuai", "chuan", "chuang", "chui", "chun", "chuo", "ci",
        "cong", "cou", "cu", "cuan", "cui", "cun", "cuo", "da", "dai", "dan", "dang", "dao", "de", "dei", "den",
        "deng", "di", "dia", "dian", "diao", "die", "ding", "diu", "dong", "dou", "du", "duan", "dui", "dun", "duo",
        "e", "en", "eng", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fiao", "fo", "fou", "fu", "ga", "gai",
        "gan", "gang", "gao", "ge", "gei", "gen", "geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang",
        "gui", "gun", "guo", "ha", "hai", "han", "hang", "hao", "he", "hei", "hen", "heng", "hong", "hou", "hu",
        "hua", "huai", "huan", "huang", "hui", "hun", "huo", "ji", "jia", "jian", "jiang", "jiao", "jie", "jin",
        "jing", "jiong", "jiu", "ju", "juan", "jue", "ka", "kai", "kan", "kang", "kao", "ke", "ken", "keng", "kong",
        "kou", "ku", "kua", "kuai", "kuan", "kuang", "kui", "kun", "kuo", "la", "lai", "lan", "lang", "lao", "le",
        "lei", "leng", "li", "lia", "lian", "liang", "liao", "lie", "lin", "ling", "liu", "lo", "long", "lou", "lu",
        "luan", "lun", "luo", "lv", "lve", "ma", "mai", "man", "mang", "mao", "me", "mei", "men", "meng", "mi",
        "mian", "miao", "mie", "min", "ming", "miu", "mo", "mou", "mu", "na", "nai", "nan", "nang", "nao", "ne",
        "nei", "nen", "neng", "ni", "nian", "niang", "niao", "nie", "nin", "ning", "niu", "nong", "nou", "nu",
        "nuan", "nun", "nuo", "nv", "nve", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei", "pen", "peng", "pi",
        "pian", "piao", "pie", "pin", "ping", "po", "pou", "pu", "qi", "qia", "qian", "qiang", "qiao", "qie", "qin",
        "qing", "qiong", "qiu", "qu", "quan", "que", "qun", "ran", "rang", "rao", "re", "ren", "reng", "ri", "rong",
        "rou", "ru", "rua", "ruan", "rui", "run", "ruo", "sa", "sai", "san", "sang", "sao", "se", "sen", "seng",
        "sha", "shai", "shan", "shang", "shao", "she", "shei", "shen", "sheng", "shi", "shou", "shu", "shua",
        "shuai", "shuan", "shuang", "shui", "shun", "shuo", "si", "song", "sou", "su", "suan", "sui", "sun", "suo",
        "ta", "tai", "tan", "tang", "tao", "te", "tei", "teng", "ti", "tian", "tiao", "tie", "ting", "tong", "tou",
        "tu", "tuan", "tui", "tun", "tuo", "wa", "wai", "wan", "wang", "wei", "wen", "weng", "wo", "wu", "xi",
        "xia", "xian", "xiang", "xiao", "xie", "xin", "xing", "xiong", "xiu", "xu", "xuan", "xue", "xun", "ya",
        "yan", "yang", "yao", "ye", "yi", "yin", "ying", "yo", "yong", "you", "yu", "yuan", "yue", "yun", "za",
        "zai", "zan", "zang", "zao", "ze", "zei", "zen", "zeng", "zha", "zhai", "zhan", "zhang", "zhao", "zhe",
        "zhei", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", "zhua", "zhuai", "zhuan", "zhuang", "zhui", "zhun",
        "zhuo", "zi", "zong", "zou", "zu", "zuan", "zui", "zun", "zuo", "walker")
        .collect(Collectors.toMap(s -> s, s -> 1));
/**
 * 拼音字典
 *
 * @return
 */
public static Map<String, Integer> getPinyinMap() {
    return stringIntegerMap;
}

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • /Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home...
    光剑书架上的书阅读 3,854评论 2 8
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,585评论 18 139
  • 一、Java 简介 Java是由Sun Microsystems公司于1995年5月推出的Java面向对象程序设计...
    子非鱼_t_阅读 4,148评论 1 44
  • 1.分类: 1)由于缺少社交途径而很难认识异性。特征:不爱社交,兴趣爱好不多 2)没时间或不愿花太多精力去结识异性...
    sarah_晴阅读 368评论 0 1
  • 中秋吃什么? 月饼、板栗、柚子……,水果,板鸭等 都不是 中秋最应该吃什么? 答曰:吃鸡 中秋节吃鸡的风俗自明代开...
    一介农夫丁建超阅读 986评论 0 1