定义,匹配如下形式的{话语},认为是会“话”内容,其他认为非会话内容:

[冒号] [左双引号] {话语}[右双引号]

先看看结果:

1.整本书会话内容与非会话内容对比:


 2. 按说话的句数(每个配对的双引号算一句)统计Top10:


 
3. 按说话的总字数统计Top10


 基本实现思路如下:

1. 下载纯文本的《红楼梦》文件,作简单的数据清洗

将西文的冒号、双引号替换为中文的冒号、双引号;

2. 提取话语,将符合话语规则的文本提取出到一个List

3.调用NPL工具包,逐句分析包含话语的上下文,找到说话的“主语”,

让主语认领每句话语。

经过比较,选型了FNLP,教程链接附上:https://github.com/xpqiu/fnlp/wiki/QuickTutorial

使用过程中,发现语义分析结果与Demo有出入,第一个标点常常被定性为词语,不明白为啥。

经过人工检验结果,发现很多人名不能正确识别,官方没有较细致的文档。

只查到可以加载自定义字典,我定义了一些人物名到 data/dict_name.txt下,并调用API加载。

贾妃 人名
丰儿 人名
尤氏 人名
贾赦 人名
金荣 人名
吴良 人名
柳氏 人名
贾芹 人名
贾珍 人名
金桂 人名
麝月 人名
晴雯 人名
元春 人名
惜春 人名
迎春 人名
探春 人名
尤二姐 人名
尤三姐 人名
紫鹃 人名
秋纹  人名
袭人  人名
空空道人    人名
士隐  人名
薛蟠  人名
林之孝 人名
女尼  人名
有人  人名
妙玉  人名
何三  人名
鸳鸯  人名
李纹  人名
湘云  人名
长史  人名
薛蝌  人名
北静王 人名
西平王 人名
王爷  人名
赵堂官 人名
衙役  人名
倪二  人名
倪家母女    人名
雨村  人名
道士  人名
巧姐  人名
巧姐儿 人名
凤姐  人名
凤姐儿 人名
秦氏  人名
贾瑞  人名
宝玉  人名
黛玉  人名
李嬷嬷 人名
薛姨妈 人名
雪雁  人名
宝钗  人名
贾蓉  人名
李纨  人名
秦钟  人名
贾母  人名
贾琏  人名
贾兰  人名
贾芸  人名
贾环  人名
平儿  人名
邢夫人 人名
王夫人 人名
众人  人名
贾蔷  人名
丫头  人名
贾政  人名
和尚  人名
程日兴 人名
王仁  人名
婆子  人名
道

4.别名问题

贾妃 元春  贾元春
凤姐  凤姐儿
巧姐  巧姐儿 

自己处理了别名映射,计数时将别名下的计数做了累加,定义在 data/map_same.txt中。

5. 工具类

package org.hl;import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;import org.fnlp.nlp.cn.CNFactory;
import org.fnlp.nlp.parser.dep.DependencyTree;
import org.fnlp.util.exception.LoadModelException;public class ChatParser {String fpath;String dict;String dict_same;String charSet;String str_all;int len_total;int len_chat;int len_sentence;List<String> ls_embrace;List<String> ls_sentence;List<String> ls_who;ArrayList<Entry<String,Integer>> who_said_sentence;ArrayList<Entry<String,Integer>> who_said_word;ArrayList<Entry<String,Integer>> who_said_per;CNFactory fm=null;HashMap<String,Integer> m_cout_sentence;HashMap<String,Integer> m_cout_word;HashMap<String,Integer> m_cout_per;HashMap<String,String> m_same=null;ChatParser(String fpath,String charSet,String dict,String fsame) throws Exception{InputStreamReader insReader = new InputStreamReader(  new FileInputStream(fpath), charSet);  this.dict = dict;this.charSet=charSet;BufferedReader br = new BufferedReader(insReader);         String line = new String(); StringBuffer sbuf = new StringBuffer();while ((line = br.readLine()) != null) {  sbuf.append(line);System.out.println(line);  }  br.close();    str_all=sbuf.toString();len_total = str_all.length();ls_embrace =new ArrayList<String>();ls_sentence =new ArrayList<String>();ls_who =new ArrayList<String>();loadSame(fsame);}public String getSameKey(String key){if(m_same==null)return key;String mk = m_same.get(key);if(mk==null)return key;elsereturn mk;}public void loadSame(String fpath) throws Exception{if(fpath==null)return;m_same = new HashMap<String,String>();InputStreamReader insReader = new InputStreamReader(  new FileInputStream(fpath), charSet);  BufferedReader br = new BufferedReader(insReader);         String line = new String(); while ((line = br.readLine()) != null) {  String[] words = line.split("\\s+");  for(int i=0,len=words.length; i<len; i++){m_same.put(words[i], line);}}  br.close();          }public void wash(){StringBuffer sbuf = new StringBuffer();StringBuffer bf = null;len_chat=0;len_sentence=0;int pos_start=0;for(int i=0,len=str_all.length(); i<len;i++){char ch = str_all.charAt(i);if(ch==':'|| ch==':'){pos_start=i;}else if((ch=='“' || ch=='\"') && bf==null){//排除非人言的双引号if(i-pos_start>3)continue;bf = new StringBuffer();sbuf.append('“');}else if ((ch=='”' || ch=='\"')&& bf!=null){String str_bf = bf.toString();len_chat +=str_bf.length();ls_sentence.add(str_bf);bf = null;sbuf.append('”');ls_embrace.add(sbuf.toString());sbuf = new StringBuffer();}else{if(bf!=null)bf.append(ch);elsesbuf.append(ch);}}len_sentence=ls_sentence.size();}public void parse() throws Exception{long tm_start = new Date().getTime();CNFactory fm = CNFactory.getInstance("models");if(this.dict!=null)fm.loadDict(dict);String who=null;HashMap<String,Integer> mc_sentence = new HashMap<String,Integer>();HashMap<String,Integer> mc_char = new HashMap<String,Integer>();for(int k=0,klen=ls_embrace.size();k<klen; k++){String str_input=ls_embrace.get(k);String[][] wc = fm.tag(str_input);DependencyTree dt =fm.parse2T(wc[0], wc[1]);//System.out.println(str_input);//System.out.println(dt);ArrayList<List<String>> ls = dt.toList();for(int i=0,len=ls.size();i<len; i++ ){List<String> cur = ls.get(i);if(//cur.get(3).equals("主语") && cur.get(1).equals("人名")){who = cur.get(0);}}ls_who.add(who);System.out.println(who+":"+ls_sentence.get(k));}long tm_span = new Date().getTime()-tm_start;System.out.println("-----------------------parse span:"+tm_span+"-----------------------------");System.out.println(len_chat+"/"+(len_total-len_chat)+"/"+len_total+":"+ls_embrace.size());}public void count_sort(){long tm_start = new Date().getTime();m_cout_sentence = new HashMap<String,Integer>();m_cout_word = new HashMap<String,Integer>();m_cout_per = new HashMap<String,Integer>();for(int k=0,klen=ls_who.size();k<klen; k++){String who = getSameKey(ls_who.get(k));String sentence = ls_sentence.get(k);int c1=1;int c2=sentence.length();if(m_cout_sentence.containsKey(who)){c1+=m_cout_sentence.get(who);c2+=m_cout_word.get(who);}//System.out.println(who+":"+c1+":"+c2+":"+sentence);m_cout_sentence.put(who, c1);m_cout_word.put(who, c2);}Iterator iter = m_cout_word.entrySet().iterator();while (iter.hasNext()) {Map.Entry<String,Integer> entry = (Map.Entry) iter.next();String key = entry.getKey();int val = entry.getValue()/m_cout_sentence.get(key);m_cout_per.put(key, val);}long tm_span = new Date().getTime()-tm_start;System.out.println("-----------------------count span:"+tm_span+"-----------------------------");who_said_sentence= new ArrayList<Entry<String,Integer>>(m_cout_sentence.entrySet());who_said_word= new ArrayList<Entry<String,Integer>>(m_cout_word.entrySet());who_said_per= new ArrayList<Entry<String,Integer>>(m_cout_per.entrySet());Collections.sort(who_said_sentence, new Comparator<Map.Entry<String, Integer>>() {     public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {     return (o2.getValue() - o1.getValue());     }  });   Collections.sort(who_said_word, new Comparator<Map.Entry<String, Integer>>() {     public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {     return (o2.getValue() - o1.getValue());    }  });      Collections.sort(who_said_per, new Comparator<Map.Entry<String, Integer>>() {     public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {     return (o2.getValue() - o1.getValue());    }  });      System.out.println("-----------------------top sentence----------------------------");int TOP =10;int pos=0;for(Entry<String,Integer> e : who_said_sentence) {  if(pos<TOP){System.out.println("{ label:'"+e.getKey() + "',value:" + e.getValue()+"},");   }else{System.out.println("{ label:'"+e.getKey() + "',value:" + e.getValue()+"}");break;}pos++;}  pos=0;System.out.println("-----------------------top word----------------------------");for(Entry<String,Integer> e : who_said_word) {   if(pos<TOP){System.out.println("{ label:'"+e.getKey() + "',value:" + e.getValue()+"},");   }else{System.out.println("{ label:'"+e.getKey() + "',value:" + e.getValue()+"}");break;}pos++;}  System.out.println("-----------------------top per----------------------------");for(Entry<String,Integer> e : who_said_per) {   if(pos<TOP){System.out.println("{ label:'"+e.getKey() + "',value:" + e.getValue()+"},");   }else{System.out.println("{ label:'"+e.getKey() + "',value:" + e.getValue()+"}");break;}pos++;}  }public static void main(String[] args) throws Exception {// TODO Auto-generated method stubChatParser cp = new ChatParser("data/t1.txt", "utf-8","data/dict_name.txt","data/map_same.txt");cp.wash();cp.parse();cp.count_sort();}}

6. 分析结果的饼状图展示, 选用了d3.js的一个pie组件,非常好用

只需要给出json格式的数据,布局完全委托给该组件了。

<script>var pie = new d3pie("pie", {header: {title: {text: "对话/非对话",fontSize: 30}},data: {content: [{ label: "对话", value: 404217 },{ label: "非对话", value: 448962}]}});
</script>

7. 性能

在IMac下,耗时毫秒数-----------------------parse span:84332-----------------------------

NLP的组件还不够理想,为了减轻其负担,双引号内的内容替换为空,再交给它处理的。

虽然如此,看着成群的对话风卷残云一半滚屏,有趣!

贾蓉:这样的大排场,我打量拿着妖怪给我们瞧瞧到底是些什么东西,那里知道是这样收罗,究竟妖怪拿去了没有?
贾珍:糊涂东西,妖怪原是聚则成形,散则成气,如今多少神将在这里,还敢现形吗!无非把这妖气收了,便不作祟,就是法力了。
贾珍:头里那些响动我也不知道,就是跟着大老爷进园这一日,明明是个大公野鸡飞过去了,拴儿吓离了眼,说得活象.我们都替他圆了个谎,大老爷就认真起来.倒瞧了个很爇闹的坛场。
贾赦:只怕是谣言罢.前儿你二叔带书子来说,探春于某日到了任所,择了某日吉时送了你妹子到了海疆,路上风恬浪静,合家不必挂念.还说节度认亲,倒设席贺喜,那里有做了亲戚倒提参起来的.且不必言语,快到吏部打听明白就来回我。
贾琏:才到吏部打听,果然二叔被参.题本上去,亏得皇上的恩典,没有交部,便下旨意,说是失察属员,重征粮米,苛虐百姓,本应革职,姑念初膺外任,不谙吏治,被属员蒙蔽,着降三级,加恩仍以工部员外上行走,并令即日回京.这信是准的.正在吏部说话的时候,来了一个江西引见知县,说起我们二叔,是很感激的,但说是个好上司,只是用人不当,那些家人在外招摇撞骗,欺凌属员,已经把好名声都弄坏了.节度大人早已知道,也说我们二叔是个好人.不知怎么样这回又参了.想是忒闹得不好,恐将来弄出大祸,所以借了一件失察的事情参的,倒是避重就轻的意思也未可知。
贾琏:先去告诉你婶子知道,且不必告诉老太太就是了。
王夫人:打听准了么?果然这样,老爷也愿意,合家也放心.那外任是何尝做得的!若不是那样的参回来,只怕叫那些混帐东西把老爷的性命都坑了呢!

源码参见附件,FNLP的m文件比较大,自己参考教程的下载链接下。

寻找《红楼梦》十大话唠相关推荐

  1. python红楼梦人数统计结果_Python学习分析红楼梦社交网络,意外发现一个有影响力的神秘人物...

    前言 这次我们将分析整个红楼梦的社交网络.我们尝试用算法去寻找红楼梦中最重要的人物,最有权势的人物,以及一些关系亲密的小团体.看看都有哪些有趣的发现吧. 社交网络 据统计,红楼梦中出场人数共有四百四十 ...

  2. 《红楼梦》后四十回真假辨析——数据挖掘之关联规则挖掘

    前言 很多人都听说过<红楼梦>的后四十回并非曹雪芹所著.本文就是用关联规则挖掘的方法,验证红楼梦后四十回与前八十回之间的用词差异. 基本概念定义 关联:自然界中某种事物发生时,其他事物也会 ...

  3. python红楼梦作者_用 Python 分析《红楼梦》,后四十回是曹雪芹所写吗?(开源)...

    原标题:用 Python 分析<红楼梦>,后四十回是曹雪芹所写吗?(开源)

  4. [转]和《红楼梦》咏菊花诗十二首

    和<红楼梦>咏菊花诗十二首 慕容雅竹 (一) 忆菊 怅对西风何所思,难忘芳菲留情时. 幽幽静静望新客,雅雅清清慰故知. 北去离人苦情远,南来归雁相思痴. 冰心一片花魂附,聚散两依应有期. ...

  5. python词频统计之红楼梦_用 Python 分析《红楼梦》,后四十回是曹雪芹所写

    用 Python 分析<红楼梦>,后四十回是曹雪芹所写 2020年11月04日 16:03:11    作者:九九文章网 处理后的效果是这个样子: #甄士隐梦幻识通灵#贾雨村风尘怀闺秀#此 ...

  6. [机器学习] --- 红楼梦后四十回到底是谁写的?机器学习分析法

    流传到今天的<红楼梦>共有120回,很多人认为是曹雪芹写了前八十回,后四十回是高鹗续写.后来随着新材料的发现,红学界经过慎重考察,认为后四十回并不是高鹗所写,高鹗和程伟元只是整理出版了&l ...

  7. 《红楼梦》-正文第三十九回名師誦読文稿

    <红楼梦>-正文第三十九回,标题:村姥姥是信口开合情哥哥偏寻根究底;正文(點聽博文誦読)如下. 话说众人见平儿来了,都说:"你们奶奶作什么呢,怎么不来了?"平儿笑道:& ...

  8. 【Python】统计《红楼梦》中出场次数前十的人物

    [Python]统计<红楼梦>中出场次数前十的人物 代码 截图 代码 import jiebaexcludes = {'什么', "一个", "我们" ...

  9. Google BERT应用之《红楼梦》对话人物提取

    作者丨庞龙刚 学校丨UC Berkeley博士后 研究方向丨高能核物理.人工智能 之前看到过一篇文章,通过提取文章中对话的人物,分析人物之间的关系,很好奇如何通过编程的方式知道一句话是谁说的.但是遍搜 ...

最新文章

  1. 数据中心“泡澡”散热,阿里云启用全球最大液冷数据中心支撑双11
  2. python如何求导数(derivative)、求偏导(partial derivative)?(sympy库symbols()函数、diff()函数、subs()函数)
  3. 找不到 javax.servlet.http.HttpServletResponse 和 javax.servlet.http.HttpServletRequest 问题解决...
  4. 思科路由器由于IP INPUT进程导致cpu负荷高的判断方法
  5. 重装linux之后gcc等下载不了,Redhat linux下安装gcc
  6. COCO 54.7mAP!DetectoRS目标检测:改进主干网,成就新高度!
  7. MariaDB 10.4.9 发布,MySQL 分支数据库
  8. python和java哪个好-Python和Java到底哪个更好?
  9. 如何测试判断云服务器的稳定性?
  10. 华硕老毛子Padavan使用IPV6+Aliddns远程管理路由
  11. RTOS 入门资料 整理
  12. 重庆—java互联网架构软件工程师学习记录—Day11(API 1)
  13. A/BTest设计方案
  14. 7-22 寻找大富翁 (25 分)
  15. OpenResty 在又拍云容器平台中的应用
  16. 微信公众号二维码不同环境差异化处理
  17. SLAM导航机器人零基础实战系列:(四)差分底盘设计——2.stm32主控软件设计
  18. 球面图绘制函数-sphere
  19. 搜狗音乐盒1.2单文件
  20. 系统重构的未来:重构工具 Coca 一周年

热门文章

  1. python 回溯_Python 回溯算法
  2. libevent库介绍
  3. 12小球找坏球的问题
  4. H3C交换机策略路由配置
  5. ToolStrip快速操作方法
  6. 什么是数据库中的一对多关系?
  7. android bugreport分析,Bugreport日志分析
  8. Pandaria(Kruskal重构树+线段树合并)
  9. HttpsTest使用百度证书检验并访问百度
  10. 2023年自动化系紫冬讲坛第3期“课程思政面对面”顺利举办