这是一个比较奇葩的需求,先说需求:
微信群聊,每个人会对boss说的话发表一下自己的感悟,需求就是将这些聊天记录中重复的部分找出来,也就是把抄袭别人感悟的人找出来。
整体设计:使用springboot开发后台接口,用户从微信拿到格式化的数据之后,在前端通过ajax发送http请求把聊天数据post到服务端,服务端进行分析之后返回结果。
1.微信群聊的格式
通过微信群聊中的“更多”–>“邮件”功能把聊天记录格式化出来,在“邮件”功能页面可以把经过格式化的聊天信息【复制】出来,然后上传我们的系统进行分析。
经过格式化的微信群聊信息:
红框位置是【换行】,蓝圈位置是【空格】。
初步分析:需要注意的是聊天记录中也可能会人为添加【换行符】,按照【换行符】截断记录会出现问题,这种思路走不通。
2.信息提取–>姓名、时间、聊天内容
把上面的已经格式化的信息进行分析:
姓名 [空格] 时间 [换行符]
[换行符]
聊天 [空格] 聊天 [换行符]
聊天 [空格] [换行符]
[换行符]
很显然应该用【空行】来分割各个信息,即把整条数据按照【[换行符] [换行符]】进行分割,也就是说用两个【换行符】进行分割,存储到数组。
所以数组中的内容就是:[姓名+时间],[聊天内容] 这种存储方式。
同样这个地方可以判断数组的length,如果为奇数,则数据切割出错。
3.信息存储–>对象
实例化一个对象用于存储一条聊天信息。
//微信消息实体类
public class WxMsg {
private int id; //数据库记录id
private String name; //言论者
private String timed; //发表言论时间
private String msg; //发表的言论
private int ischeck; //是否已经被检查
private String islike; //和哪条记录相似
public WxMsg() {
ischeck=0;
islike=null;
}
get&set()
}
接下来就是把数组中的内容放到对象中,然后把对象存到一个List中。
4.数据转移:数组–>list
数组中,偶数位元素表示[姓名+时间],显然要分割提取出姓名、时间。由于姓名的格式存在多样性,所以应该从时间入手。经过考虑,决定把【姓名+时间】这个字符串从尾部截取5个字符,剩下的字符串去空格,经过这样操作就可分析出姓名、时间:
【赵 旭东 19:46】–> 【赵旭东】、【19:46】
List<WxMsg> wxMsgList = new ArrayList<WxMsg>();//用于存储微信信息实体的集合
//按照\n\n分割字符串存进数组 [姓名 时间] [聊天信息]
String[] wxmsg_arr=wxmsgstr.split("\n\n");
if (wxmsg_arr.length%2 == 1){
System.out.println("格式错误:"+wxmsg_arr[wxmsg_arr.length-1]);
return "error";
}
//else
System.out.println("共解析出的聊天记录条数:"+wxmsg_arr.length/2);
//将数组中的信息提取到对象中并存储
for(int i=0; i<wxmsg_arr.length;i=i+2){
WxMsg wxMsg = new WxMsg();
//取出时间
wxMsg.setTimed(wxmsg_arr[i].substring(wxmsg_arr[i].length()-5));
//取出姓名
wxMsg.setName(wxmsg_arr[i].substring(0,wxmsg_arr[i].length()-6));
//存聊天内容
wxMsg.setMsg(wxmsg_arr[i+1]);
System.out.println("数据转移arr-list:"+wxMsg.toString());
wxMsgList.add(wxMsg);
}
将每条记录都存到对象中,然后存储到list中,那么list中的数据就是:老的聊天信息在前面,新的聊天信息在后面。
list.get(i); —> i越大,信息越新
5.重复度检查
这是这个系统的核心,也是后期继续优化的重点位置,目前没有采用任何高级算法,只是先实现这个检查功能。
- 第一步:这也是第一层循环,从后向前遍历List(i=max –> i=0)。至于为什么要从后向前遍历?一定要先检查最后一个人说的,检查的是看当前【被检查人】和前面的聊天记录是否重复,第一个发表的人当然不需要检查。
- 第二步:从list中取出当前对象的一个【聊天记录】,把这个【聊天记录】按照各种标点符合进行分割,分割成若干句话,存到数组msg[]中。
- 第三步:第二层循环,循环遍历存储当前对象聊天记录的数组msg[],接下来就是判断数组中存放的每一句话和list中其他对象的[聊天记录]是否相似。
- 第四步:第三层循环,遍历存放对象的list(i=this-1 –> i=0),从【当前对象的位置-1】开始遍历,一直遍历到【开头】,当然这里遍历的方向无所谓,重点是要覆盖当前对象位置之前的记录。在这层循环中需要判断上层的msg[i]这句话和那个对象的[聊天记录相似],如果相似,就进行记录。
//分析查重
/*
j:当前在被查的人 z:当前被查的人的第几句话 y:被比对的人()
*/
System.out.println("分析查重测试");
//从新到老把聊天记录遍历一遍(最老的数据当然不需要检查)
for(int j=wxMsgList.size()-1;j>0;j--){
//切分这个人的聊天信息
String[] per_msg = wxMsgList.get(0).getMsg().split("[、,。;?!,.;?\\n]");
//用上面的分析方法,遇上标点加换行会产生空数据
//遍历这些聊天数据
for(int z=0;z<per_msg.length;z++){
//每句聊天记录去匹配比他老的聊天信息
for(int y=j-1;y>=0;y--){
if("".equals(per_msg[z])){
//聊天记录是空的,不匹配
}else {
int rs = wxMsgList.get(y).getMsg().indexOf(per_msg[z]);
if(rs==-1){
}else {
analysestr = analysestr +
wxMsgList.get(j).getName()+"在时间:"+wxMsgList.get(j).getTimed()
+"说的第"+(z+2)+"句(大约)抄袭"+wxMsgList.get(y).getName()
+"在时间:"+wxMsgList.get(y).getTimed()
+"说的第"+rs+"个字往后 <br /> <br />";
System.out.println(analysestr);
}
}
}
}
}