package dao;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

public class JaroWinklerDistanceDao {
	
	private static final String html_seperator="\n";
    private static final String sentence_seperator="[,.;!:,。;!:]";
    //将一段文字切割成若干句
    public static String[] split(String src)
    {
        List<String> result=new ArrayList<>();
        String []htmls=src.split(html_seperator);
        for (String s:htmls){
            for (String s2:s.split(sentence_seperator)){
                result.add(s2);
            }
        }
        String []results=new String[result.size()];
        result.toArray(results);//集合转数组
        
        return results;
    }
    //清晰字符串除杂消除干扰
    public static String[] clean(String []src)
    {
        for (int i=0;i<src.length;i++)
        {
            src[i]=clean(src[i]);//调用清楚非数字、字母、中文的方法,赋予新数组
        }
        return src;
    }
    //清除非数字、字母、中文
    public static String clean(String src)
    {
        return src.replaceAll("[^a-zA-Z0-9\\u4e00-\\u9fa5]","");
    }
    //检测两个作业内容的相似率
    public static float detect(String des,String src)
    {
        float resultFloat=0.00f;
        float tmp = 0.00f;
        float sm = 0.00f;
        //分语义行切割作业内容
        String desArray[]=split(des);
        String srcArray[]=split(src);
        //对作业内容中非自然语言进行清洗除杂
        desArray=clean(desArray);
        srcArray=clean(srcArray);
        /*System.out.println(desArray.length+"  "+srcArray.length);
        for(String s:desArray){
        	System.out.println(s);
        }*/
        for (String s:desArray){
        	sm = 0.00f;
        	for(String pr:srcArray){
        		tmp = 0.00f;
        		tmp = getDistance(s,pr);
        		sm = sm>tmp?sm:tmp;
//        		System.out.println("tmp:"+tmp);
        	}
//        	System.out.println(sm);
        	resultFloat += sm;
        }
//        System.out.println(sm);
        resultFloat/=desArray.length;
        return resultFloat;
    }
    
    private static int max(int length, int length2) {
		// TODO Auto-generated method stub
    	return length>length2 ? length:length2;
	}
	//将小数转化为百分数的字符串
    public static String transferFloatToPersentString(float f)
    {
        String result;
        f*=10000;
        int t1=(int)f;
       result=(((float)t1)/100)+"%";
        return result;
    }
    public static String check() {
        Date start=new Date();
        //将路径存在字符串变量中,调用in方法读取。
        String path1 = "D:/tmp/论文库.txt";
        String path2 = "D:/tmp/学生论文.txt";
        String tar=in(path2);
        String src=in(path1);
        String sim = transferFloatToPersentString(detect(tar,src));
        System.out.println("相似度:" + sim);
        Date end=new Date();
        System.out.println("花费时间:"+(end.getTime()-start.getTime())+"毫秒");
        return sim;
    }
    
    public static String in(String path)
	{
		String str="";
		File file=new File(path);
		try {
		 FileInputStream in=new FileInputStream(file);
		 // size 为字串的长度 ,这里一次性读完
		 int size=in.available();
		 byte[] buffer=new byte[size];
		 in.read(buffer);
		 in.close();
		 str=new String(buffer,"UTF-8");
		} catch (IOException e) {
		 // TODO Auto-generated catch block
		 e.printStackTrace();
		 return null;
		}
		return str;
		
/* 按行读对于要处理的格式化数据是一种读取的好方式 */
		/*int len=0;
		 StringBuffer str=new StringBuffer("");
		 File file=new File("D:\\tmp\\论文.txt");
		 try {
		  FileInputStream is=new FileInputStream(file);
		  InputStreamReader isr= new InputStreamReader(is,"utf-8");
		  BufferedReader in= new BufferedReader(isr);
		  String line=null;
		  while( (line=in.readLine())!=null )
		  {
		   if(len != 0) // 处理换行符的问题
		   {
		    str.append("\r\n"+line);
		   }
		   else
		   {
		    str.append(line);
		   }
		   len++;
		  }
		  in.close();
		  is.close();
		 } catch (IOException e) {
		  // TODO Auto-generated catch block
		  e.printStackTrace();
		 }
		 
		 return str.toString();*/
	}
    
    
    //JaroWinklerDistance算法
    
    private static float threshold = 0.7f;
    
	  private static int[] matches(String s1, String s2) {
	    String max, min;
	    if (s1.length() > s2.length()) {
	      max = s1;
	      min = s2;
	    } else {
	      max = s2;
	      min = s1;
	    }
	    // 两个分别来自s1和s2的字符如果相距不超过 floor(max(|s1|,|s2|) / 2) -1, 我们就认为这两个字符串是匹配的
	    // 因此,查找时,超过此距离则停止
	    int range = Math.max(max.length() / 2 - 1, 0);
	    // 短的字符串, 与长字符串匹配的索引位
	    int[] matchIndexes = new int[min.length()];
	    Arrays.fill(matchIndexes, -1);
	    // 长字符串匹配的标记
	    boolean[] matchFlags = new boolean[max.length()];
	    // 匹配的数目
	    int matches = 0;
	    // 外层循环,字符串最短的开始
	    for (int mi = 0; mi < min.length(); mi++) {
	      char c1 = min.charAt(mi);
	      // 可能匹配的距离,包括从给定位置从前查找和从后查找
	      for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max
	          .length()); xi < xn; xi++) {
	    	// 排除被匹配过的字符,若找到匹配的字符,则停止
	        if (!matchFlags[xi] && c1 == max.charAt(xi)) {
	          matchIndexes[mi] = xi;
	          matchFlags[xi] = true;
	          matches++;
	          break;
	        }
	      }
	    }
	    
	    // 记录min字符串里匹配的字符串,保持顺序
	    char[] ms1 = new char[matches];
	    // 记录max字符串里匹配的字符串,保持顺序
	    char[] ms2 = new char[matches];
	    for (int i = 0, si = 0; i < min.length(); i++) {
	      if (matchIndexes[i] != -1) {
	        ms1[si] = min.charAt(i);
	        si++;
	      }
	    }
	    for (int i = 0, si = 0; i < max.length(); i++) {
	      if (matchFlags[i]) {
	        ms2[si] = max.charAt(i);
	        si++;
	      }
	    }
	    
	    // 查找换位的数目
	    int transpositions = 0;
	    for (int mi = 0; mi < ms1.length; mi++) {
	      if (ms1[mi] != ms2[mi]) {
	        transpositions++;
	      }
	    }
	    
	    // 查找相同前缀的数目
	    int prefix = 0;
	    for (int mi = 0; mi < min.length(); mi++) {
	      if (s1.charAt(mi) == s2.charAt(mi)) {
	        prefix++;
	      } else {
	        break;
	      }
	    }
	    
	    // 返回匹配数目(m),换位的数目(t),相同的前缀的数目,字符串最长
	    return new int[] { matches, transpositions / 2, prefix, max.length() };
	  }
	 
	  public static float getDistance(String s1, String s2) {
	    int[] mtp = matches(s1, s2);
	    //  返回匹配数目(m)
	    float m = (float) mtp[0];
	    if (m == 0) {
	      return 0f;
	    }
	    
	    // Jaro Distance
	    float j = ((m / s1.length() + m / s2.length() + (m - mtp[1]) / m)) / 3;
	    
	    // 计算Jaro-Winkler Distance, 这里调整分数的因数=Math.min(0.1f, 1f / mtp[3])
	    float jw = j < getThreshold() ? j : j + Math.min(0.1f, 1f / mtp[3]) * mtp[2]
	        * (1 - j);
	    return jw;
	  }
	 
	  /**
	   * Sets the threshold used to determine when Winkler bonus should be used.
	   * Set to a negative value to get the Jaro distance.
	   * @param threshold the new value of the threshold
	   */
	  public void setThreshold(float threshold) {
	    this.threshold = threshold;
	  }
	 
	  /**
	   * Returns the current value of the threshold used for adding the Winkler bonus.
	   * The default value is 0.7.
	   * @return the current value of the threshold
	   */
	  public static float getThreshold() {
	    return threshold;
	  }

}
最近下载更多
呵呵喝  LV4 3月11日
杨豫川  LV12 1月12日
asddwh  LV13 2023年12月29日
微信网友_6680567232876544  LV8 2023年10月8日
hongdongdong  LV14 2023年6月27日
tianyuboy111  LV3 2023年5月20日
liuchang183  LV5 2023年4月22日
蹇金金  LV7 2023年3月14日
北方菜  LV11 2022年12月30日
Korol27  LV3 2022年12月16日
最近浏览更多
yimaoermao  LV1 11月28日
xiaoaitx  LV4 11月19日
angaochong  LV5 10月16日
breeza 10月9日
暂无贡献等级
时光海  LV2 6月30日
破剑茶寮  LV4 6月26日
liyan54188  LV2 6月25日
zzk3085000785 6月20日
暂无贡献等级
TY0165  LV20 6月19日
顶部 客服 微信二维码 底部
>扫描二维码关注最代码为好友扫描二维码关注最代码为好友