利用 Levenshtein距离 计算两个字符串的相似度

编辑距离(Edit Distance),又称Levenshtein距离,是指两个字串之间,由一个转成另一个所需的最少编辑操作次数。
许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。一般来说,编辑距离越小,两个串的相似度越大。

例如将kitten一字转成sitting:
        sitten (k→s) 
        sittin (e→i) 
        sitting (→g)
 俄罗斯科学家@ Vladimir Levenshtein 在1965年提出这个概念。 

 

 


package com.test;


/**
 * 编辑距离(Edit Distance),又称Levenshtein距离,是指两个字串之间,由一个转成另一个所需的最少编辑操作次数。
 * 许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。一般来说,编辑距离越小,两个串的相似度越大。
 * 
 * 
 * 	例如将kitten一字转成sitting:
 * 		sitten (k→s) 
 * 		sittin (e→i) 
 * 		sitting (→g)
 *  俄罗斯科学家@ Vladimir Levenshtein 在1965年提出这个概念。 
 * 
 * 
 * @author Lenovo
 *
 */
public class SimilarityUtil {
	
	/**
	 * 求三个数中最小的哪一个
	 * @param one
	 * @param two
	 * @param three
	 * @return
	 */
	private static int min(int one, int two, int three) {
		int min = one;
		if (two < min) {
			min = two;
		}
		if (three < min) {
			min = three;
		}
		return min;
	}

	/**
	 * 求编辑距离
	 * @param str1
	 * @param str2
	 * @return
	 */
	public static int ld(String str1, String str2) {
		int d[][]; // 矩阵
		int n = str1.length();
		int m = str2.length();
		int i; // 遍历str1的
		int j; // 遍历str2的
		char ch1; // str1的
		char ch2; // str2的
		int temp; // 记录相同字符,在某个矩阵位置值的增量,不是0就是1
		if (n == 0) {
			return m;
		}
		if (m == 0) {
			return n;
		}
		d = new int[n + 1][m + 1];
		for (i = 0; i <= n; i++) { // 初始化第一列
			d[i][0] = i;
		}
		for (j = 0; j <= m; j++) { // 初始化第一行
			d[0][j] = j;
		}
		for (i = 1; i <= n; i++) { // 遍历str1
			ch1 = str1.charAt(i - 1);
			// 去匹配str2
			for (j = 1; j <= m; j++) {
				ch2 = str2.charAt(j - 1);
				if (ch1 == ch2) {
					temp = 0;
				} else {
					temp = 1;
				}
				// 左边+1,上边+1, 左上角+temp取最小
				d[i][j] = min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1]
						+ temp);
			}
		}
		return d[n][m];
	}

	/**
	 * 计算相似度
	 * @param str
	 * @param target
	 * @return
	 */
	public static double sim(String str, String target) {
		  //去除空白字符、换行、标点符号
        String regex = "[\\pP\\p{Punct}\\s]";
        return 1 - (float) ld(str.replaceAll(regex, ""), target.replaceAll(regex, "")) / Math.max(str.length(), target.length());
		
		
		//int ld = ld(str1, str2);
		//return 1 - (double) ld / Math.max(str1.length(), str2.length());
	}
	
	/**
	 * 判断两个字符串相似度,可设置level
	 * @param strSource 原字符串
	 * @param strCompared 比较字符串
	 * @param level 评分阀值
	 * @param moreCount 比较字符串比原字符串多多少个限制
	 * @return
	 */
	public static Boolean isSimilar(String strSource,String strCompared,int level,int moreCount){
	   if(strCompared.length()-strSource.length()>moreCount){
	      return false;
	   }
	   int count=strSource.length();
	   int maxSameCount=0;
	   //遍历count次
	   for(int i=0;i<count;i++){
	      int nowSameCount=0;
	      int c=0;
	      int lastIndex=0;//记录上一次匹配的目标索引
	      //遍历每一次的原字符串所有字段
	      for(int j=i;j<strSource.length();j++){
	         char charSource=strSource.charAt(j);
	         for(;c<strCompared.length();c++){
	            char charCompare=strCompared.charAt(c);
	            if(charSource==charCompare){
	               nowSameCount++;
	               lastIndex=++c;//如果匹配,手动加1
	               break;
	            }
	         }
	         c=lastIndex;//遍历完目标字符串,记录当前匹配索引
	      }
	      if(nowSameCount>maxSameCount){
	         maxSameCount=nowSameCount;
	      }
	   }
	   //大于原字符串数量的情况
	   if(maxSameCount>count){
	      maxSameCount=count-(maxSameCount-count);
	   }
	   double dLv= (double)100*maxSameCount/count;
	   int iLv=10*maxSameCount/count*10;
	   int cha=(int)dLv-iLv;
	   int yu=cha>5?1:0;
	   iLv+=yu*10;
	   if(iLv/10>=level){
	      return true;
	   }else{
	      return false;
	   }
	}

	public static void main(String[] args) {

		String str1 = "灵武市白土岗乡泾兴村防洪工程(一期)";
		String str2 = "灵武市白土岗乡泾兴村防洪工程(二期)";
		//System.out.println("ld=" + ld(str1, str2));
		System.out.println("相似度" + sim(str1, str2));
		
		System.out.println(isSimilar(str1, str2, 9, 4)?"字符串相似":"字符串不相似");
		
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值