首页 > 代码库 > 城市查询-拼音、全拼、简拼、混拼、卷舌音、前后鼻音、兼容查询C#与nodejs+redis应用---笔记

城市查询-拼音、全拼、简拼、混拼、卷舌音、前后鼻音、兼容查询C#与nodejs+redis应用---笔记

第一步:用C#实现拼音的全拼简拼卷舌音,前后鼻音兼容等功能。并建立redis所需查询索引等。
只是简单实现了该功能,对性能无优化。前提条件:城市拼音手动建立好。如:北京 全拼  BeiJing  区分大小写,简拼BJ 。简拼可有可无,没有的话,自己截取出来即可。
代码如下:
public class SpellIndexHelper
    {
        /// <summary>
        /// 声母
        /// </summary>
        private static string[,] initialsList = new string[3, 2] { { "Z", "Zh" }, { "C", "Ch" }, { "S", "Sh" } };

        /// <summary>
        /// 韵母 Finals 
        /// </summary>
        private static string[,] finalsList = new string[5, 2] { { "an", "ang" }, { "en", "eng" }, { "in", "ing" }, { "An", "Ang" }, { "En", "Eng" } };

        /// <summary>
        /// 声母加韵母
        /// </summary>
        private static string[,] spellList = new string[8, 2] { { "Z", "Zh" }, { "C", "Ch" }, { "S", "Sh" }, { "an", "ang" }, { "en", "eng" }, { "in", "ing" }, { "An", "Ang" }, { "En", "Eng" } };

        #region 包含函数

        /// <summary>
        /// 中文名称匹配
        /// </summary>
        /// <param name="value"></param>
        /// <param name="query"></param>
        /// <returns></returns>
        public static bool IsChineseMatch(string value, string query)
        {
            if (string.IsNullOrWhiteSpace(query) || string.IsNullOrWhiteSpace(value)) return false;
            if (query.Length > value.Length) return false;
            int len = query.Length;
            return value.ToLower().Substring(0, len).Contains(query.ToLower());

        }
        /// <summary>
        /// 全拼匹配
        /// </summary>
        /// <param name="value"></param>
        /// <param name="query"></param>
        /// <returns></returns>
        public static bool IsSpellMatch(string value, string query)
        {
            if (string.IsNullOrWhiteSpace(query) || string.IsNullOrWhiteSpace(value)) return false;
            string queryAppend = Append(query).ToLower();
            int len = queryAppend.Length;
            if (len > value.Length) return false;
            return value.ToLower().Substring(0, len).ToLower().Contains(queryAppend);
        }

        #endregion

        /// <summary>
        /// 追加模糊匹配的全部增量(BeiJin->BeiJing)
        /// </summary>
        /// <param name="spell"></param>
        /// <returns></returns>
        public static string Append(string spell)
        {
            //for (int i = 0; i < 8; i++)
            //{
            //    spell = spell.Replace(spellList[i, 0], spellList[i, 1]);
            //}
            //spell = spell.Replace("hh", "h");
            //spell = spell.Replace("gg", "g");
            //return spell;
            return Append(spell, false);
        }

        /// <summary>
        /// 追加模糊匹配的全部增量并转换为小写(BeiJin->beijing)
        /// </summary>
        /// <param name="spell"></param>
        /// <param name="isLower"></param>
        /// <returns></returns>
        public static string Append(string spell, bool isLower)
        {
            spell = isLower ? spell.ToLower() : spell;
            if (spell == "shijiazhuang")
            {

            }
            for (int i = 0; i < 8; i++)
            {
                spell = isLower ? spell.Replace(spellList[i, 0].ToLower(), spellList[i, 1].ToLower()) : spell.Replace(spellList[i, 0], spellList[i, 1]);
            }
            spell = spell.Replace("hh", "h");
            spell = spell.Replace("gg", "g");
            return spell;
        }

        /// <summary>
        /// 追加声母
        /// </summary>
        /// <param name="spell"></param>
        /// <returns></returns>
        public static string AppendInitials(string spell)
        {
            for (int i = 0; i < 3; i++)
            {
                spell = spell.Replace(initialsList[i, 0], initialsList[i, 1]);
            }
            spell = spell.Replace("hh", "h");
            return spell;
        }

        /// <summary>
        /// 追加韵母
        /// </summary>
        /// <param name="spell"></param>
        /// <returns></returns>
        public static string AppendFinals(string spell)
        {
            for (int i = 0; i < 5; i++)
            {
                spell = spell.Replace(finalsList[i, 0], finalsList[i, 1]);
            }
            spell = spell.Replace("gg", "g");
            return spell;
        }

        /// <summary>
        /// 去掉模糊匹配全部增量(beijing->beijin)
        /// </summary>
        /// <param name="spell"></param>
        /// <returns></returns>
        public static string Remove(string spell)
        {
            for (int i = 0; i < 8; i++)
            {
                spell = spell.Replace(spellList[i, 1], spellList[i, 0]);
            }
            return spell;
        }

        /// <summary>
        /// 去掉模糊匹配声母
        /// </summary>
        /// <param name="spell"></param>
        /// <returns></returns>
        public static string RemoveInitials(string spell)
        {
            for (int i = 0; i < 3; i++)
            {
                spell = spell.Replace(initialsList[i, 1], initialsList[i, 0]);
            }
            return spell;
        }

        /// <summary>
        /// 去掉模糊匹配韵母
        /// </summary>
        /// <param name="spell"></param>
        /// <returns></returns>
        public static string RemoveFinals(string spell)
        {
            for (int i = 0; i < 5; i++)
            {
                spell = spell.Replace(finalsList[i, 1], finalsList[i, 0]);
            }
            return spell;
        }


        /// <summary>
        /// 根据大小写分割拼音(BeiJing,分割为Bei Jing)
        /// </summary>
        /// <param name="spell"></param>
        /// <returns></returns>
        public static List<string> SplitSpell(string spell)
        {
            if (string.IsNullOrWhiteSpace(spell))
            {
                return null;
            }
            int length = spell.Length;
            List<string> list = new List<string>();
            string splitPY = null;
            for (int i = 0; i < length; i++)
            {
                if (char.IsUpper(spell, i))//大写
                {
                    if (splitPY != null)
                        list.Add(splitPY);
                    splitPY = null;//清空
                    splitPY += spell.Substring(i, 1);
                    if (i == length - 1)//如果是最后一个
                    {
                        list.Add(splitPY);
                    }
                }
                if (char.IsLower(spell, i))//小写
                {
                    splitPY += spell.Substring(i, 1);
                    if (i == length - 1)//如果是最后一个
                    {
                        list.Add(splitPY);
                    }
                }
            }
            return list;
        }


        /// <summary>
        /// 简拼/全拼 全适配索引 
        /// </summary>
        /// <param name="oldSpell">每个元素为单个拼音 (简拼/全拼 非补全)</param>
        /// <param name="newSpell">每个元素为单个拼音 (简拼/全拼 补全 ) </param>
        /// <returns></returns>
        private static string GetCombination(List<string> oldSpell, List<string> newSpell)
        {
            int length = oldSpell.Count;
            string result = null; ;
            for (int i = 0; i < length; i++)
            {
                string combinationResult = null;
                for (int j = 0; j < length; j++)
                {
                    if (i == j)
                    {
                        combinationResult += oldSpell[i];
                    }
                    else
                    {
                        combinationResult += newSpell[j];
                    }
                }
                result += combinationResult + ";";
            }
            return result;
        }

        /// <summary>
        /// 创建所有混拼索引
        /// </summary>
        /// <param name="shortSpell"></param>
        /// <param name="spell"></param>
        /// <returns></returns>
        public static string CreateHybridIndex(string shortSpell, string spell)
        {
            List<List<string>> list = new List<List<string>>(); //第一层有多少个分割的拼音,第二层拼音
            list.Add(SplitSpell(shortSpell));                   //添加原始数据---简拼
            list.Add(SplitSpell(AppendInitials(shortSpell)));   //添加补全声母---简拼
            list.Add(SplitSpell(spell));                        //添加原始数据---全拼
            list.Add(SplitSpell(AppendInitials(spell)));        //添加补全声母---全拼
            list.Add(SplitSpell(Append(spell)));                //添加补全-------全拼
            list.Add(SplitSpell(AppendFinals(spell)));          //添加补全韵母---全拼
            list.Add(SplitSpell(RemoveInitials(spell)));        //移除所有声母---全拼
            list.Add(SplitSpell(RemoveFinals(spell)));          //移除所有韵母---全拼
            list.Add(SplitSpell(Remove(spell)));                //移除所有-------全拼

            string result = null;
            foreach (var item1 in list)
            {
                foreach (var item2 in list)
                {
                    if (item1 != item2)
                    {
                        result += GetCombination(item1, item2);
                    }
                }
            }
            return Distinct(result);
        }
        /// <summary>
        /// 去重
        /// </summary>
        /// <param name="hybridSpell"></param>
        /// <returns></returns>
        private static string Distinct(string hybridSpell)
        {
            var list = hybridSpell.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Distinct();
            string result = null;
            foreach (var item in list)
            {
                result += item + ";";
            }
            return result.Substring(0, result.Length - 1);
        }
    }
C#调用
<pre class="csharp" name="code"> string shortSpell = SpellIndexHelper.Append(list[i].ShorSpell.Trim());//StrCityCodeHelper.GetNewShortSpell(list[i].ShorSpell.Trim());
                string spell = SpellIndexHelper.Append(list[i].Spell.Trim());//StrCityCodeHelper.GetNewSpell(list[i].Spell.Trim());
              

   list[i].SpellIndex = SpellIndexHelper.CreateHybridIndex(list[i].ShorSpell.Trim(), list[i].Spell.Trim());
                _insuranceRegionService.Updata(list[i]);


生成混拼索引后存入SQL数据库中,效果如下:
技术分享
第二步:用nodejs实现查询功能。
nodejs的异步真的很操蛋啊,真是个陷阱。从redis取数据的时候真麻烦。
nodejs 代码如下:
var dbHelper = require('../../WebApi/MSSQL/dbHelper.js');
var cluster = require('cluster');
var numCPUs = require('os').cpus().length;

//var idd=1;
/*dbHelper.select("dbo.[InsuranceRegion]",1,"where id=@id",{id: idd},"order by id",function(err,result){
 console.log(result);
 });*/
//dbHelper.select("dbo.InsuranceRegion","","","","order by RegionId",function(err,result){
//console.log(result);
//});
var redis = require("redis");
var express = require("express");
var app=express();
var  isSuccess =false;
var client  = redis.createClient('6379', '192.168.151.87');
// redis 链接错误
client.on("error", function(error) {
    console.log(error);
});
var convertNullToEmptyStr=function(data){
    return data==null?"":data;
};
var convertToBool=function(data){
    return data==null?0:1;
};
/*
var json = "{'name':'aa','age':18}";
var jsonobj = eval('('+json+")");
for (var key in jsonobj) {
    console.log(key)
}*/
var sql ="SELECT  [InsuranceRegion].[RegionId]  ,[CityID]    ,[Name]    ,[Spell]    ,[FullName]    ,[Level]    ,[OrderNumber]    ,[ShorSpell]    ,[HotFlag]    ,[HotOrderNumber]    ,[LicensePlateCode]   ,[SpellAdapter] ,[YGBX]    ,[CCIC]    ,[AXATP]    ,[PICC]    ,[CPIC]    ,[PAIC]    ,[ZABX] FROM [Finance].[dbo].[InsuranceRegion] left  join [InsuranceRegionMapping] on [InsuranceRegion].RegionId =[InsuranceRegionMapping].GBCode"
dbHelper.querySql(sql,"",function(err,result){
    for (var i in result){
        client.hmset(
            "baoxian:Region:RegionId:"+result[i].RegionId,
            "RegionId",result[i].RegionId,
            "CityID", convertNullToEmptyStr(result[i].CityID),
            "Name", convertNullToEmptyStr(result[i].Name),
            "Spell",convertNullToEmptyStr(result[i].Spell),
            "FullName", convertNullToEmptyStr(result[i].FullName),
            "Level",  convertNullToEmptyStr(result[i].Level),
            "OrderNumber",  convertNullToEmptyStr(result[i].OrderNumber),
            "ShorSpell",  convertNullToEmptyStr(result[i].ShorSpell),
            "HotFlag", convertNullToEmptyStr( result[i].HotFlag),
            "HotOrderNumber",  convertNullToEmptyStr( result[i].HotOrderNumber),
            "LicensePlateCode",  convertNullToEmptyStr( result[i].LicensePlateCode),
           // "ShorSpellAdapter",  convertNullToEmptyStr( result[i].ShorSpellAdapter),
            "SpellAdapter",  convertNullToEmptyStr( result[i].SpellAdapter),
            "YGBX",convertToBool( result[i].YGBX),
            "CCIC",convertToBool( result[i].CCIC),
            "AXATP",convertToBool( result[i].AXATP),
            "PICC",convertToBool( result[i].PICC),
            "CPIC",convertToBool( result[i].CPIC),
            "PAIC",convertToBool( result[i].CPIC),
            "ZABX",convertToBool( result[i].CPIC)
        );
        if(result[i].Level==2){//建立城市索引
            client.sadd(["baoxian:Region:Level:2", result[i].RegionId], function(err, reply) {
            //console.log(reply); // 1
            });
            createQueryIndex(result[i].Name,result[i].RegionId);
            createQueryIndex(result[i].FullName,result[i].RegionId);     
            createQuerySpell(result[i].SpellAdapter,result[i].RegionId);
        }
        else if(result[i].Level==1){//建立省索引
            client.sadd("baoxian:Region:Level:1",result[i].RegionId);
        }
        else if(result[i].Level==3){//建立城镇区县索引
            client.sadd("baoxian:Region:County:CityID:"+result[i].RegionId.toString().substring(0,4)+"00",result[i].RegionId);
        }
    }
});
/*
dbHelper.select("dbo.InsuranceRegion","","","","order by RegionId",function(err,result){
    //console.log(result);
    for (var i in result){
        client.hmset(
            "baoxian:Region:RegionId:"+result[i].RegionId,
            "CityID", convertNullToEmptyStr(result[i].CityID),
            "Name", convertNullToEmptyStr(result[i].Name),
            "Spell",convertNullToEmptyStr(result[i].Spell),
            "FullName", convertNullToEmptyStr(result[i].FullName),
            "Level",  convertNullToEmptyStr(result[i].Level),
            "OrderNumber",  convertNullToEmptyStr(result[i].OrderNumber),
            "ShorSpell",  convertNullToEmptyStr(result[i].ShorSpell),
            "HotFlag", convertNullToEmptyStr( result[i].HotFlag),
            "HotOrderNumber",  convertNullToEmptyStr( result[i].HotOrderNumber),
            "LicensePlateCode",  convertNullToEmptyStr( result[i].LicensePlateCode)
        );
        if(result[i].Level==2){//建立城市索引
            client.sadd(["baoxian:Region:Level:2", result[i].RegionId], function(err, reply) {
                //console.log(reply); // 1
            });
            createQueryIndex(result[i].Name,result[i].RegionId);
            createQueryIndex(result[i].Spell,result[i].RegionId);
            createQueryIndex(result[i].FullName,result[i].RegionId);
            createQueryIndex(result[i].ShorSpell,result[i].RegionId);
        }
        else if(result[i].Level==1){//建立省索引
            client.sadd("baoxian:Region:Level:1",result[i].RegionId);
        }
        else if(result[i].Level==3){//建立城镇区县索引
            client.sadd("baoxian:Region:County:CityID:"+result[i].RegionId.toString().substring(0,4)+"00",result[i].RegionId);
        }
    }
});
*/
var createQuerySpell=function(data,regionId){
    console.log(data);
    var arry = data.split(";") ;
    for(var i in arry){
        if(arry[i]!="")
        {
            createQueryIndex(arry[i],regionId);
        }
    }
}
//建立查询索引
var createQueryIndex=function(data,regionId){
    var len = data.length;
    for(var i=1;i<=len;i++){
        client.sadd(["baoxian:Region:Query:"+ data.toLowerCase().substring(0,i),regionId], function(err, reply) {
            //console.log(reply); // 1
        });
    }
};
//建立移动站热点城市查询
var createMHotCityIndex=function(){
   var mHotCityIndex=new Array(110100,310100,440100,440300,320100,320500,330100,370100,370200,420100,430100,210100,510100,500100,610100,340100,350100,220100,130100,410100,120100,210200);
    for (var i in mHotCityIndex){
        client.sadd(["baoxian:Region:MHotCity",mHotCityIndex[i]], function(err, reply) {
            //console.log(reply); // 1
        });
        // client.zadd("baoxian:Region:HotCity",result[i].HotOrderNumber,result[i].RegionId);
    }
};
createMHotCityIndex();
dbHelper.select("dbo.InsuranceRegion","","where Level=2 and HotFlag=1 ","","order by [HotOrderNumber]",function(err,result){
    //console.log(result);
    for (var i in result){
        client.sadd(["baoxian:Region:HotCity",result[i].RegionId], function(err, reply) {
            //console.log(reply); // 1
        });
       // client.zadd("baoxian:Region:HotCity",result[i].HotOrderNumber,result[i].RegionId);
    }
});
if (cluster.isMaster) {
    // Fork workers. fock num of CPUS - 1 works
    for (var i = 1; i <= numCPUs; i++) {
        cluster.fork();
    }

    cluster.on('exit', function(worker, code, signal) {
        console.log('worker ' + worker.process.pid + ' died');
    });
    cluster.on('fork', function(worker, code, signal) {
        console.log('worker ' + worker.process.pid + ' is online');
    });
} else {
    app.get('/CityQuery', function(req, res) {
        res.writeHead(200, {
            "Content-Type": "text/plain;charset=utf-8"
        });
        var data={
            Result:true,
            Message:null,
            Data:null
        };
        try  {
            var key = req.query.key;
            console.log(key);
            var jsonp = req.query.jsoncallback;
            key=decodeURIComponent(key).toLowerCase();
            if(key==""|| key == null || key == undefined){
                data.Result=false;
                data.Message ="查询参数为空!";
                res.end(jsonp+"("+JSON.stringify(data)+")");
            }
            else{
                client.smembers('baoxian:Region:Query:'+key, function(err, reply) {
                    var len = reply.length
                    console.log(len); console.log(reply);
                    if(len==0) {
                        //data.Result=t;
                        data.Message ="没有匹配项!";
                        return res.end(jsonp + "(" + JSON.stringify(data) + ")");
                    }
                    var queryResult=new Array([len]);
                    var j=0;
                    for(var i=0 ;i<len;i++) {
                        client.hgetall("baoxian:Region:RegionId:" + reply[i], function (err, replyData) {
                            queryResult[j]=replyData;
                            j++;
                            if(queryResult[len-1]!=undefined){
                                data.Data = queryResult;
                                res.end(jsonp+"("+JSON.stringify(data)+")");
                            }
                        });
                    }
                });
            }
        }
        catch (error){
            console.log("[error]:"+error.name+error.message);
            res.end(error.name+error.message);
        }

        //WriteLogs(isSuccess,res);
        //res.end("数据提交完毕!");
        //console.log(req.query.key);

    });
    app.get('/HotCity', function(req, res) {
        var data={
            Result:true,
            Message:null,
            Data:null
        };
        try  {
            var jsonp =req.query.jsoncallback;
            console.log(jsonp);
            client.smembers('baoxian:Region:HotCity', function(err, reply) {
                var len = reply.length;
                var queryResult=new Array([len]);
                var j=0;
                for(var i=0 ;i<len;i++) {
                    client.hgetall("baoxian:Region:RegionId:" + reply[i], function (err, replyData) {
                        queryResult[j]=replyData;
                        j++;
                        if(queryResult[len-1]!=undefined){
                            data.Data = queryResult;
                            //console.log(jsonp+JSON.stringify(queryResult));
                            res.end(jsonp+"("+JSON.stringify(data)+")");
                        }
                    });
                }
            });
        }
        catch (error){
            console.log("[error]:"+error.name+error.message);
            res.end(error.name+error.message);
        }
        res.writeHead(200, {
            "Content-Type": "text/plain;charset=utf-8"
        });
        //WriteLo
    });
    app.get('/HotMCity', function(req, res) {

    });
    app.listen(9800);
}
nodejs查询效果如下:
技术分享

城市查询-拼音、全拼、简拼、混拼、卷舌音、前后鼻音、兼容查询C#与nodejs+redis应用---笔记