AutoCompleteBox是一个常见的提高输入效率的组件,很多WPF的第三方控件库都提供了这个组件,但基本都是字符串的子串匹配,不支持拼音模糊匹配,例如无法通过输入ldhliudehua匹配到刘德华。要实现拼音模糊搜索功能,通常会采用分词、数据库等技术对待匹配数据集进行预处理。某些场景受制于条件限制,无法对数据进行预处理,本文将介绍在这种情况下如何实现支持拼音模糊搜索的AutoCompleteBox,先来看下实现效果。

主要思路

WPF中并没有AutoCompleteBox控件,我们可以使用TextBox输入搜索内容,用Popup+ListBox显示匹配到的提示内容。拼音模糊匹配汉字则采用字符串匹配的方式来解决,也就是搜索字符串和待匹配数据集的内容全部转换为拼音字符串,然后进行子串匹配。这里有三个问题需要解决。

  1. 汉字转换为拼音。
  2. 拼音如何匹配。 例如ldhlidhldhualiudehuadhuahua等都能匹配到刘德华
  3. 匹配后的内容高亮显示。 当输入dhua匹配到刘德华时需要把德华两个字高亮。

汉字转换拼音

微软为了开发者实现国际化语言的互转,提供了Microsoft Visual Studio International Pack,这个扩展包里面有中文、日文、韩文、英语等各国语言包,并提供方法实现互转、获取拼音、获取字数、甚至获取笔画数等等。下载Microsoft Visual Studio International Pack 1.0 SR1安装后,在安装目录中找到ChnCharInfo.dll,然后在项目中添加引用。

ChnCharInfo.dll获取汉字的拼音时只能传入单个字符,因此只能把汉字字符串拆分成一个个字符处理,由于汉字存在多音字情况以及缺少语义信息,获取的拼音组合可能是多个,例如输入长江,返回的是changjiangzhangjiang。汉字转拼音的方法如下:

/// <summary>
/// 获取汉字拼音
/// </summary>
/// <param name="str">待处理包含汉字的字符串</param>
/// <param name="split">拼音分隔符</param>
/// <returns></returns>
public static List<string> GetChinesePhoneticize(string str, string split = "")
{
List<string> result = new List<string>();
char[] chs = str.ToCharArray();
Dictionary<int, List<string>> totalPhoneticizes = new Dictionary<int, List<string>>();
for (int i = 0; i < chs.Length; i++)
{
var phoneticizes = new List<string>();
if (ChineseChar.IsValidChar(chs[i]))
{
ChineseChar cc = new ChineseChar(chs[i]);
phoneticizes.AddRange(cc.Pinyins.Where(r => !string.IsNullOrWhiteSpace(r)).ToList<string>().ConvertAll(p => Regex.Replace(p, @"\d", "").ToLower()).Distinct());
}
else
{
phoneticizes.Add(chs[i].ToString());
}
if (phoneticizes.Any())
totalPhoneticizes[i] = phoneticizes;
} foreach (var phoneticizes in totalPhoneticizes)
{
var items = phoneticizes.Value;
if (result.Count <= 0)
{
result = items;
}
else
{
var newtotalPhoneticizes = new List<string>();
foreach (var totalPingYin in result)
{
newtotalPhoneticizes.AddRange(items.Select(item => totalPingYin + split + item));
}
newtotalPhoneticizes = newtotalPhoneticizes.Distinct().ToList();
result = newtotalPhoneticizes;
}
}
return result;
}

拼音匹配算法

汉字转换后的拼音字符串有多组,只要搜索字符串转换的拼音组合有一组与待匹配字符串转换的拼音组合中匹配,则认为匹配成功,为了后续高亮显示,需要记录下匹配的起始位置以及匹配的子串长度。代码如下:

public static bool fuzzyMatchChar(string character, string input, out int matchStart, out int matchCount)
{
List<string> regexs = GetChinesePhoneticize(input);
List<string> targetStr = GetChinesePhoneticize(character, " ");
matchStart = -1;
matchCount = 0;
foreach (string regex in regexs)
{
foreach (string target in targetStr)
{
if (PhoneticizeMatch(regex, target.Split(' '), out matchStart, out matchCount))
return true;
}
}
return false;
}

这里的PhoneticizeMatch方法是拼音匹配算法的核心,是在【算法】拼音匹配算法这篇博文中算法的基础上稍作修改,详细的思路及图解可阅读这篇博文。

高亮匹配的子串

WPF中可以通过TextEffectPositionStartPositionCount以及Foreground属性设置字符串中需要高亮内容的起始位置、长度以及高亮颜色。前面拼音匹配算法中获取了匹配成功子串的起始位置和长度,也正是为此做准备。之前在WPF使用TextBlock实现查找结果高亮显示一文中有详细介绍思路和代码,此处不再赘述。

小结

本文介绍了在不依赖数据库及分词的情况下如何实现拼音模糊搜索并在目标字符串中高亮显示,方法中也存在诸多不足需要完善的地方。

  1. 匹配策略存在误匹配。例如输入,可以匹配出拼音为shi的所有汉字。
  2. 匹配算法效率不够高。测试过程中,待匹配数据集中模拟了500条数据,匹配耗时大概在400~500ms左右。

代码示例

ChinesePhoneticizeFuzzyMatch

[WPF] 脱机环境实现支持拼音模糊搜索的AutoCompleteBox的更多相关文章

  1. ES6笔记(1) -- 环境配置支持

    系列文章 -- ES6笔记系列 虽然ES6已经发布一年多了,但在各大浏览器之中的支持度还不是很理想,在这查看ES6新特性支持度 Chrome的最新版本浏览器大部分已经支持,在Node.js环境上支持度 ...

  2. php检测iis环境是否支持htaccess

    php检测iis环境是否支持htaccess的方法. modrewrite.php <?php echo "mod_rewrite works"; ?> open_me ...

  3. Windows Presentation Foundation (WPF) 项目中不支持xxx的解决

    一般Windows Presentation Foundation (WPF) 项目中不支持xxx都是由于没引用相应的程序集导致,比如Windows Presentation Foundation ( ...

  4. 关于liunx 机器脱机环境(netcore)Nuget包迁移的问题

    首先nuget脱机环境是没办法加载第三方nuget包的,我这里的做法是使用nuget缓存文件(正确的做法还是推荐使用自己搭建的nuget服务器然后正常发布,这里只是做应急之需) 我们都知道项目的dot ...

  5. 【.NET6+WPF+Avalonia】开发支持跨平台的WPF应用程序以及基于ubuntu系统的演示

    前言:随着跨平台越来越流行,.net core支持跨平台至今也有好几年的光景了.但是目前基于.net的跨平台,大多数还是在使用B/S架构的跨平台上:至于C/S架构,大部分人可能会选择QT进行开发,或者 ...

  6. 解决c#,wpf程序带环境安装包体积太大问题

    在.net开发客户端的时候,一定会遇到用户没有安装.net环境的问题,特别是现在win7,win8,win10多系统并用的时间段,很多开发者使用的是4.5的目标环境,用户却是使用win7的系统,这样势 ...

  7. WPF ItemsControl 控件支持鼠标滚轮滑动

    此文章意在解决在WPF中ItemsControl类型的集合控件支持鼠标滚轮操作,并可控制滚动的速度. 第一步:给ItemsControl添加滚轮事件. this.listBox.AddHandler( ...

  8. 转:windows下使用gvim搭建简单的IDE编译环境(支持C/C++/Python等)

    原文来自于:http://www.cnblogs.com/zhuyp1015/archive/2012/06/16/2552269.html 使用gvim在windows环境下搭建简单的IDE环境可以 ...

  9. 扩展ArcGIS API for Silverlight/WPF 中的TextSymbol支持角度标注

    原文 http://blog.csdn.net/esricd/article/details/7587136 在ArcGIS API for Silverlight/WPF中原版的TextSymbol ...

  10. mac环境下支持PHP调试工具xdebug,不需要建项目server

    先让php支持xdebug 方式一: https://xdebug.org/download.php 下载相应的xdebug  可以到http://xdebug.org/wizard.php 把php ...

随机推荐

  1. Java 8 中Stream用法

    Stream是Java 8新增的接口,Stream可以认为是一个高级版本的 Iterator. 废话不多说直接上代码 package com.example.demo; import org.juni ...

  2. python+k8s——基础练习

    列表 core_api = client.CoreV1Api() # 管理核心资源(Pod, Service, ConfigMap 等) apps_api = client.AppsV1Api() # ...

  3. Linux驱动--IOCTL实现

    参考:[Linux]实现设备驱动的ioctl函数_哔哩哔哩_bilibili.<Linux设备驱动程序(中文第三版).pdf> 1 用户空间ioctl 用户空间的ioctl函数原型,参数是 ...

  4. MySQL 导出一条数据的插入语句

    1.MySQL 导出一条数据的插入语句的方法 在MySQL中,如果我们想要导出一条数据的插入语句,我们可以使用SELECT ... INTO OUTFILE语句(但这通常用于将整个表或查询结果导出到一 ...

  5. .NET8 Hello World!

    ​ 使用ASP.NET Core Web Application模板创建的Empty项目如下: ​ 这是一个最简单的Web项目,运行起来会在根路径响应Hello World! 2.1.1 Progra ...

  6. Mybatis-MySQL 中使用IFNUL

    Mybatis-MySQL 中使用IFNULL(p1,p2)函数但是有一些需要注意的地方. 假设数据 title: student id name age 1 Ann 18 2 Bom 19 3 He ...

  7. __proto__和[[Prototype]]的区别

    __proto__和[[Prototype]]的区别 先看下面这一段代码: const obj1 = Object.create(null); // very plain object obj1.__ ...

  8. AES加密和解密,key需要32位

    AES加密和解密,key需要32位 package com.example.core.mydemo.sign; import org.apache.commons.codec.binary.Base6 ...

  9. Java8 - sum求和,将 List 集合转为 Map,key去重(groupingBy),sorted排序

    Java8 - sum求和,将 List 集合转为 Map,key去重(groupingBy),sorted排序 package com.example.core.mydemo.java8; publ ...

  10. 实验六-Salt本地pojie实验

    [实验目的]了解Salt型密码的加密机制,学会使用本地密码pojie工具来pojieSalt型密码,了解pojie密码原理. [知识点]Salt,密码pojie [实验原理] 1.Salt概念 在密码 ...