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. 运算符优先级 JAVA11

    **运算符优先级 ** 规律:算术运算符优先级较高,关系和逻辑运算符优先级较低.多数运算符具有左结合性,单目运算符.三目运算符.赋值运算符具有右结合性. 运算符的优先级 举例 使用优先级为 1 的小括 ...

  2. Wpf Bitmap(Image)Base64,Url,文件Path,Stream转BitmapSource(ImageSource),无需外部dll

    直接上代码 using System; using System.Drawing; using System.IO; using System.Windows.Forms; using System. ...

  3. latex图片格式问题解决(viso转PDF转eps)

    latex图片格式问题解决(viso->PDF->eps) 1.viso绘图 如何让界面自动适应图的大小? 设计->大小->适应绘图 如何将VISIO图转换为PDF? 文件-& ...

  4. nginx获取后端真实IP,添加后端服务器响应时间并记录日志

    nginx获取后端真实IP,添加后端服务器响应时间并记录日志 1.日志定义 log_format nginx '$remote_addr - $remote_user [$time_local] &q ...

  5. QuartusII调用 PLL_IP核方法(Mega Wizard)

    [基本信息] 要求:调用PLL-IP核,50Mhz晶振输入,输出四路时钟不同信号:100Mhz,25Mhz,50Mhz(90°相位),50Mhz(20%占空比). 芯片型号:cyclone Ⅳ EP4 ...

  6. 代码审计——基础(JAVAEE)

    JAVAEE 目录 JAVAEE 常见框架 Struct2(控制层) Hibernate(持久层(与数据库交互)(不用再写简单的sql语句,但是需要一些列复杂的配置文件))(全ORM模型) Sprin ...

  7. LeetCode 688. Knight Probability in Chessboard “马”在棋盘上的概率 (C++/Java)

    题目: On an NxN chessboard, a knight starts at the r-th row and c-th column and attempts to make exact ...

  8. ETL工具-nifi干货系列 第六讲 处理器JoltTransformJSON

    1.处理器作用 使用Jolt转换JSON数据为其他结构的JSON,成功的路由到'success',失败的'failure'.处理JSON的实用程序不是基于流的,因此大型JSON文档转换可能会消耗大量内 ...

  9. work02

    第一题: 看程序说答案 int a = 10; int b = 3; int c = a + b;//13 int d = a - b;//7 int e = a * b; //30 int f = ...

  10. 增补博客 第三篇 python 英文统计

    编写程序实现对特定英文文章(文本文件)的单词数和有效行数的统计,其中要求空行不计数: def count_words_and_lines(file_path): word_count = 0 line ...