Android快速拨号匹配算法(二)

接上篇,下面是几个匹配算法的详情:

1.完全匹配

完全匹配很简单了,只要判断string是否相等就行了。这里要判断所有拼音和所有号码。如果拼音已经符合,就不再判断号码。反正是一个人……

	private ScoreAndHits completeMatch(String reg) {
		ScoreAndHits scoreAndHits = new ScoreAndHits(-1, 0f,
				new ArrayList<PointPair>());

		for (int i = 0; i < fullNameNumberWithoutSpace.size(); i++) {
			String str = fullNameNumberWithoutSpace.get(i);
			if (reg.equals(str)) {
				scoreAndHits.nameIndex = i;
				scoreAndHits.score = Match_Level_Complete;
				scoreAndHits.pairs.add(new PointPair(i, -1));
				scoreAndHits.matchLevel = Level_Complete;
				return scoreAndHits;
			}
		}

		for (int i = 0; i < phones.size(); i++) {
			PhoneStruct phone = phones.get(i);
			if (reg.equals(phone.phoneNumber)) {
				scoreAndHits.nameIndex = i;
				scoreAndHits.score = Match_Level_Complete;
				scoreAndHits.pairs.add(new PointPair(i, -1));
				scoreAndHits.matchType = Match_Type_Phone;
				scoreAndHits.matchLevel = Level_Complete;
				return scoreAndHits;
			}
		}
		// 走到这里说明没有匹配
		return new ScoreAndHits(-1, 0f, new ArrayList<PointPair>());
	}

2.前置首字母溢出匹配。(能不能想个好听的名字

private ScoreAndHits foreAcronymOverFlowMatch(String reg) {
        // 因为有可能是多音字,所以这个方法用来对比不同拼音的匹配度,并取最大的那个
	ScoreAndHits scoreAndHits = new ScoreAndHits(-1, 0f,
			new ArrayList<PointPair>());
	for (int i = 0; i < fullNameNumber.size(); i++) {
		ArrayList<String> names = fullNameNumber.get(i);
		ScoreAndHits tmpscore = foreAcronymOverFlowMatch(names, reg);
		if (tmpscore.score > scoreAndHits.score) {
			scoreAndHits = tmpscore;
			scoreAndHits.nameIndex = i;
		}
	}
	scoreAndHits.matchLevel = Level_Fore_Acronym_Overflow;
	return scoreAndHits;
}

// 在第一个字母确定的情况下,第二个字母有可能有三种情况
// 一、在第一个字母所在单词的邻居位置charAt(x+1);
// 二、在第二个单词的首字母处
// 三、以上两种情况皆不符合,不匹配,出局

private ScoreAndHits foreAcronymOverFlowMatch(ArrayList<String> names,
		String reg) {
	// 用来得出某一个拼音的匹配值。
	ScoreAndHits scoreAndHits = new ScoreAndHits(-1, 0f,
			new ArrayList<PointPair>());
	if (names.get(0).charAt(0) == reg.charAt(0)) {
	        //其实crossWords()方法才是求匹配值的方法,lol
		OverflowMatchValue value = crossWords(names, reg, 0, 0, 0);
		int cross = crossWords(names, reg, 0, 0, 0).crossed;
		if (cross > 0) {
			scoreAndHits.score = Match_Level_Fore_Acronym_Overflow + cross
					* Match_Score_Reward - (names.size() - cross)
					* Match_Miss_Punish;
			scoreAndHits.pairs = value.pairs;
		}

	}
	return scoreAndHits;
}

/**
 * 返回一串字符能跨越另一串字符的长度,根据上面的匹配规则,要尽可能的多匹配单词。若要保证
 * 能匹配最长的长度,只要保证下一个字符开始的一段字符能匹配
 * 最长的长度即可,换名话说,如果想要让96758匹配最长的字符串,那么只要保证6758能匹配最长
 * 的字符串即可,然后758,再然后58……。例如,名字叫PanAnNing,输入pan,那么应该匹配三个
 * 首字母,PAN,而不是第一姓的拼音Pan.
 * 这是一个递归。
 * 
 * @param names
 * @param regString
 *            匹配字符串
 * @param listIndex
 *            匹配到的list的第listIndex个单词
 * @param strIndex
 *            匹配到第listIndex个单词中的第strIndex个字母
 * @param regIndex
 *            regchar的匹配位置,比如匹配到了96758的7上,也就是regIndex==2.
 * @return
 */
private OverflowMatchValue crossWords(ArrayList<String> names,
		String regString, int listIndex, int strIndex, int regIndex) {
	OverflowMatchValue result = new OverflowMatchValue(0, false);
	OverflowMatchValue reser = new OverflowMatchValue(0, false);
	OverflowMatchValue impul = new OverflowMatchValue(0, false);
	if (regIndex < regString.length() - 1) {
		char nextChar = regString.charAt(regIndex + 1);
		if (listIndex < names.size() - 1
				&& nextChar == names.get(listIndex + 1).charAt(0)) {
			impul = crossWords(names, regString, listIndex + 1, 0,
					regIndex + 1);
		}
		if (strIndex < names.get(listIndex).length() - 1
				&& nextChar == names.get(listIndex).charAt(strIndex + 1)) {
			reser = crossWords(names, regString, listIndex, strIndex + 1,
					regIndex + 1);
		}
	} else {
		result = new OverflowMatchValue((strIndex == 0) ? 1 : 0, true);
		result.pairs.add(0, new PointPair(listIndex, strIndex));
	}

	if (reser.matched || impul.matched) {
		if (impul.crossed > reser.crossed) {
			result = impul;
		} else {
			result = reser;
		}
		result.matched = true;
		result.crossed = ((strIndex == 0) ? 1 : 0)
				+ Math.max(result.crossed, result.crossed);
		result.pairs.add(0, new PointPair(listIndex, strIndex));
	}
	return result;
}

static class OverflowMatchValue {
	public int crossed = 0;
	public boolean matched = false;
	public ArrayList<PointPair> pairs = new ArrayList<PointPair>();

	public OverflowMatchValue(int c, boolean m) {
		this.crossed = c;
		this.matched = m;
	}
}

3.后置首字母溢出匹配。(能不能想个好听的名字

跟前置首字母溢出匹配基本一样,只不过匹配的第一个字母不再是姓的首字母。

private ScoreAndHits backAcronymOverFlowMatch(String reg) {
        //跟上面差不多
	ScoreAndHits scoreAndHits = new ScoreAndHits(-1, 0f,
			new ArrayList<PointPair>());
	for (int i = 0; i < fullNameNumber.size(); i++) {
		ArrayList<String> names = fullNameNumber.get(i);
		ScoreAndHits tmp = backAcronymOverFlowMatch(names, reg);
		if (tmp.score > scoreAndHits.score) {
			scoreAndHits = tmp;
			scoreAndHits.nameIndex = i;
		}
	}
	scoreAndHits.matchLevel = Level_Back_Acronym_Overflow;
	return scoreAndHits;
}

private ScoreAndHits backAcronymOverFlowMatch(ArrayList<String> names,
		String reg) {
	int score = 0;
	int punish = 0;
	ScoreAndHits scoreAndHits = new ScoreAndHits(-1, 0f,
			new ArrayList<PointPair>());
	// 有可能会调用多次crossWords,取决于名字的长度。这是跟前面的不同
	for (int i = 0; i < names.size(); i++) {
		String string = (String) names.get(i);
		if (string.charAt(0) == reg.charAt(0)) {
			OverflowMatchValue value = crossWords(names, reg, i, 0, 0);
			int cross = value.crossed;
			int lost = names.size() - cross;
			if (cross > score || cross == score && punish > lost) {
				scoreAndHits.pairs = value.pairs;
				score = cross;
				punish = lost;
			}
		}
	}
	if (score > 0) {
		scoreAndHits.score = Match_Level_Back_Acronym_Overflow + score
				* Match_Score_Reward - punish * Match_Miss_Punish;
		return scoreAndHits;
	} else {
		return new ScoreAndHits(-1, 0f, new ArrayList<PointPair>());
	}

}

4.后置无头匹配。(难听就难听了,反正就那个意思)

private ScoreAndHits backHeadlessParagraphMatch(String reg) {
	int punish = 0;
	ScoreAndHits scoreAndHits = new ScoreAndHits(-1, -1f,
			new ArrayList<PointPair>());
	scoreAndHits.matchLevel = Level_Headless;
	scoreAndHits.matchType = Match_Type_Phone;
	// 算了不匹配姓名了,假设没人会得这么离谱
	for (int i = 0; i < phones.size(); i++) {
		PhoneStruct phone = phones.get(i);
		int sco = phone.phoneNumber.indexOf(reg);
		if (sco >= 0) {
			int lost = phone.phoneNumber.length() - reg.length();
			if (scoreAndHits.score < sco || sco == scoreAndHits.score
					&& punish > lost) {
				scoreAndHits.score = sco;
				scoreAndHits.nameIndex = i;
				// 尽管有可能匹配的字符串很长,但是因为是连贯的,所以只要
				// add一个就够啦
				scoreAndHits.pairs.add(new PointPair(i, sco));
				punish = lost;
			}
		}
	}
	if (scoreAndHits.score >= 0) {
		scoreAndHits.score = Match_Level_Headless - scoreAndHits.score
				* Match_Score_Reward - punish * Match_Miss_Punish;
	}
	return scoreAndHits;
}




到这里已经可以得出输入字符串与联系人的匹配度了,剩下的事情就是调用和显示了,但是这不是本文的重点

时间: 2024-10-14 09:47:37

Android快速拨号匹配算法(二)的相关文章

Android快速拨号匹配算法(一)

快速拨号是指,呃不用解释了,国内拨号软件都带的大家都知道. 快速匹配,很容易想到的就是先把九宫格输入键盘上输入的数字转换成可能的拼音组合,然后再用这些可能的拼音与联系人列表中的姓名拼音一一匹配,取匹配度最高的排到最前,但是这有一个问题就是数组对应的可能的拼音组合实在是点儿多,跑一下下面的代码就知道了.如果想智能一些的话还要先剔除一些不可能的拼音组合实在有点麻烦. public static HashMap<Character, String[]> keyMaps; public static 

android快速上手(二)android开发环境搭建及hello world

基本了解了java语法,下一步,我们一起开启hello world的神秘之旅. (一)android开发环境搭建 之前搭建android开发环境是件非常费力的事情,下载Eclipse,安装ADT等,如今android官方给我们提供了全套配置. https://developer.android.com/sdk/index.html 搭建android开发环境之前记得先安装jdk (二)开启Hello World之旅 (1)创建Hello World项目 安装完带ADT的Eclipse,打开Ecl

【Android快速入门】目录结构及adb命令【附Android拨号器的实现,自作】

目录结构 src: 存放java代码 gen: 存放自动生成文件的. R.java 存放res文件夹下对应资源的id project.properties: 指定当前工程采用的开发工具包的版本 libs: 当前工程所依赖的jar包. assets: 放置一些程序所需要的媒体文件. bin: 工程的编译目录. 存放一些编译时产生的临时文件和当前工程的.apk文件. res(resources): 资源文件. drawable: 存放程序所用的图片. layout: 存放android的布局文件.

Bmob移动后端云服务平台--Android从零开始--(二)android快速入门

Bmob移动后端云服务平台--Android从零开始--(二)android快速入门 上一篇博文我们简单介绍何为Bmob移动后端服务平台,以及其相关功能和优势.本文将利用Bmob快速实现简单例子,进一步了解它的强大之处. 一.准备工作 1.注册Bmob账号 在网址栏输入www.bmob.cn或者在百度输入Bmob进行搜索,打开Bmob官网后,点击右上角的"注册",在跳转页面填入你的姓名.邮箱.设置密码,确认后到你的邮箱激活Bmob账户,你就可以用Bmob轻松开发应用了. 2.网站后台创

【Android快速入门2】拨号器的实现

拨号器是个很简单的布局,用来做Android的入门最好不过. 本程序给予Android API19编译实现,因此是新版布局.不习惯的请注意. 截图下次我有空补上. 1.Java主程序: public class MainActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setC

Android基础篇之Android快速入门--你必须要知道的基础

Android快速入门 1. 搭建开发环境 >解压压缩文件,得到:①Android SDK   (类似于JDK)② Eclipse  ③ADT >配置两个path环境变量:D:\adt-bundle-windows-x86\sdk\platform-tools:D:\adt-bundle-windows-x86\sdk\tools >配置基本的Eclipse的设置: 调整字体大小,字符集,配置android sdk的位置 >创建模拟器: 2. 创建第一个Android项目: Hel

看大师讲解Android快速开发框架EasyAndroid

前几天做了小应用,感觉小有成就,名字叫"长见识了",是一款趣味答题类的游戏,题目各种火爆各种经典,下载地址,看似一个简单的答题小游戏却是五脏俱全,从开发流程上都进行了严格的规范,大家有空可以下载玩玩~ 在这个应用中,用到了我以前集成的一个快速开发框架-EasyAndroid,这个框架我以前在做项目的时候总结,整理出来的,对于快速开发Android应用非常实用. 其实,Android应用的开发并不难,我们拿到一款Android应用后,百分之九十以上无外乎有这么几个功能: 1,IOC Mo

android快速上手(三)常用控件使用

完成了android的第一个程序HelloWorld,下面就开始控件的学习,下面是一些常见的控件. (一)TextView 简单的文本描述 (二)EditText 编辑框,输入文字信息 (三)Button 按钮,点击后会触发点击事件,可以对事件进行处理 (四)ImageView 图片控件,可以加载图片显示 (五)ListView 列表,需要跟适配器Adapter结合,适配器提供数据 (六)Toast 闪现提示语,常用于普通的提示文本,只显示一小段时间自动消失 (七)ScrollView 一般用于

Xamarin.Android快速入门

一.准备工作 1.创建一个空的解决方案,并命名为Phoneword 2.右击解决方案 新建->新建项目 并命名为Phoneword_Droid 二.界面 1.打开Resources文件夹->layout文件夹双击打开Main.axml 2.然后将会出现下面的界面 3.接着我们选择这个Button并删除(按下Delete),并从左边的工具箱中拖拽一个 Text(Large) 控件到该界面中,如下所示: 4.同时还要通过属性窗口修改Text的值: 5.紧接着拖拽一个Plain Text控件到之前的