中文分词程序实验报告含源代码
中文分词代码
中文分词代码(此代码为作者多年经验总结,以前发表过VB,PB版本)Posted on 2006-03-24 18:18 JackYang阅读(582) 评论(0)编辑收藏/** created by yzh 2004.5.12* 请大家引用时保留这段作者声明,此代码为开源代码;使用不受限制,欢迎大家采用本人所写JS动态拖动表格实现代码。
* 中文分词代码*此代码为作者多年经验总结,以前发表过VB,PB版本*/importjava.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.util.Locale;import java.util.TreeMap;import java.util.TreeSet;public class ChineseSegmenter {private static ChineseSegmentersegmenter = null;// private Hashtablezhwords;private TreeMapzhwords;privateTreeSetcforeign, cnumbers;// Char formpublic final static int TRAD = 0;public final static int SIMP = 1;public final static int BOTH = 2;// Charform is TRAD, SIMP or BOTHprivate ChineseSegmenter(intcharform, booleanloadwordfile) {cforeign = new TreeSet();cnumbers = new TreeSet();if (charform == SIMP) {loadset(cnumbers, "data/snumbers_u8.txt");loadset(cforeign, "data/sforeign_u8.txt");} else if (charform == TRAD) {loadset(cnumbers, "data/tnumbers_u8.txt");loadset(cforeign, "data/tforeign_u8.txt");} else { // BOTHloadset(cnumbers, "data/snumbers_u8.txt");loadset(cforeign, "data/sforeign_u8.txt");loadset(cnumbers, "data/tnumbers_u8.txt");loadset(cforeign, "data/tforeign_u8.txt");}// zhwords = new Hashtable(120000);zhwords = new TreeMap();if (!loadwordfile) {return;}String newword = null;try {InputStreamworddata = null;if (charform == SIMP) {worddata = getClass().getResourceAsStream("simplexu8.txt");} else if (charform == TRAD) {worddata = getClass().getResourceAsStream("tradlexu8.txt");} else if (charform == BOTH) {worddata = getClass().getResourceAsStream("bothlexu8.txt");}BufferedReader in = new BufferedReader(new InputStreamReader( worddata, "UTF8"));while ((newword = in.readLine()) != null) {if ((newword.indexOf("#") == -1) && (newword.length() < 5)) {zhwords.put(newword.intern(), "1");if (newword.length() == 3) {if (zhwords.containsKey(newword.substring(0, 2).intern()) == false) {zhwords.put(newword.substring(0, 2).intern(), "2");}}if (newword.length() == 4) {if (zhwords.containsKey(newword.substring(0, 2).intern()) == false) {zhwords.put(newword.substring(0, 2).intern(), "2");}if (zhwords.containsKey(newword.substring(0, 3).intern()) == false) {zhwords.put(newword.substring(0, 3).intern(), "2");}}}}in.close();} catch (IOException e) {e.printStackTrace();}}public synchronized static void reset() {ChineseSegmenter.segmenter = null;}public synchronized static ChineseSegmentergetGBSegmenter() {Locale.setDefault(Locale.SIMPLIFIED_CHINESE);if (ChineseSegmenter.segmenter == null) {ChineseSegmenter.segmenter = new ChineseSegmenter(ChineseSegmenter.SIMP, true); }return ChineseSegmenter.segmenter;}public synchronized static ChineseSegmenter getBig5Segmenter() {Locale.setDefault(Locale.TRADITIONAL_CHINESE);if (ChineseSegmenter.segmenter == null) {ChineseSegmenter.segmenter = new ChineseSegmenter(ChineseSegmenter.TRAD, true); }return ChineseSegmenter.segmenter;}private void loadset(TreeSettargetset, String sourcefile) {String dataline;try {InputStreamsetdata = getClass().getResourceAsStream(sourcefile);BufferedReader in = new BufferedReader(new InputStreamReader(setdata, "UTF-8"));while ((dataline = in.readLine()) != null) {if ((dataline.indexOf("#") > -1) || (dataline.length() == 0)) {continue;}targetset.add(dataline.intern());}in.close();} catch (Exception e) {System.err.println("Exception loading data file" + sourcefile + " "+ e);e.printStackTrace();}}publicbooleanisNumber(String testword) {boolean result = true;for (int i = 0; i <testword.length(); i++) {if (cnumbers.contains(testword.substring(i, i + 1).intern()) == false) {result = false;break;}}return result;}publicbooleanisAllForeign(String testword) {boolean result = true;for (int i = 0; i <testword.length(); i++) {if (cforeign.contains(testword.substring(i, i + 1).intern()) == false) {result = false;break;}}return result;}publicbooleanisNotCJK(String testword) {boolean result = true;for (int i = 0; i <testword.length(); i++) {if (Character.UnicodeBlock.of(testword.charAt(i)) == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS) {result = false;break;}}return result;}public String segmentLine(String cline, String separator) {StringBuffercurrentword = new StringBuffer();StringBuffer outline = new StringBuffer();int i, clength;char currentchar;// separator = " ";clength = cline.length();for (i = 0; i <clength; i++) {currentchar = cline.charAt(i);if (Character.UnicodeBlock.of(currentchar) == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS|| isNumber(cline.substring(i, i + 1)) == true) {// Character in CJK blockif (currentword.length() == 0) { // start looking for next// wordif (i > 0&& (Character.isWhitespace(cline.charAt(i - 1)) == false)) {outline.append(separator);}currentword.append(currentchar);} else {if (zhwords.containsKey(new String(currentword.toString()+ currentchar).intern()) == true&& ((String) (zhwords.get(new String(currentword .toString()+ currentchar).intern()))).equals("1") == true) {// word is in lexiconcurrentword.append(currentchar);} else if (isAllForeign(currentword.toString())&&cforeign.contains(new String(new char[] { currentchar }).intern())&& i + 2 <clength&& (zhwords.containsKey(cline.substring(i, i + 2) .intern()) == false)) {// Possible a transliteration of a foreign name currentword.append(currentchar);} else if (isNumber(currentword.toString())&&cnumbers.contains(new String(new char[] { currentchar }).intern())/** && (i + 2 <clength) &&* (zhwords.containsKey(cline.substring(i, i+2).intern()) == * false)*/) {// Put all consecutive number characters together currentword.append(currentchar);} else if ((zhwords.containsKey(new String(currentword .toString()+ currentchar).intern()))&& (((String) (zhwords.get(new String(currentword .toString()+ currentchar).intern()))).equals("2") == true) && i + 1 <clength&& (zhwords.containsKey(new String(currentword .toString()+ currentchar + cline.charAt(i + 1)).intern()) == true)) {// Starts a word in the lexiconcurrentword.append(currentchar);} else { // Start anewoutline.append(currentword.toString());if (Character.isWhitespace(currentchar) == false) {outline.append(separator);}currentword.setLength(0);currentword.append(currentchar);}}} else { // Not chinese character// System.err.println("not cjk");if (currentword.length() > 0) {outline.append(currentword.toString());if (Character.isWhitespace(currentchar) == false) {outline.append(separator);}currentword.setLength(0);}outline.append(currentchar);}}outline.append(currentword.toString());returnoutline.toString();// return offsets;}public static void main(String[] args) throws Exception {ChineseSegmenterseg = ChineseSegmenter.getGBSegmenter();System.out.println(seg.segmentLine("Some string in chinese.", " "));}}分类: java类。
实验一、词法分析器(含源代码)
词法分析器实验报告一、实验目的及要求本次实验通过用C语言设计、编制、调试一个词法分析子程序,识别单词,实现一个C语言词法分析器,经过此过程可以加深对编译器解析单词流的过程的了解。
运行环境:硬件:windows xp软件:visual c++6.0二、实验步骤1.查询资料,了解词法分析器的工作过程与原理。
2.分析题目,整理出基本设计思路。
3.实践编码,将设计思想转换用c语言编码实现,编译运行。
4.测试功能,多次设置包含不同字符,关键字的待解析文件,仔细察看运行结果,检测该分析器的分析结果是否正确。
通过最终的测试发现问题,逐渐完善代码中设置的分析对象与关键字表,拓宽分析范围提高分析能力。
三、实验内容本实验中将c语言单词符号分成了四类:关键字key(特别的将main说明为主函数)、普通标示符、常数和界符。
将关键字初始化在一个字符型指针数组*key[]中,将界符分别由程序中的case列出。
在词法分析过程中,关键字表和case列出的界符的内容是固定不变的(由程序中的初始化确定),因此,从源文件字符串中识别出现的关键字,界符只能从其中选取。
标识符、常数是在分析过程中不断形成的。
对于一个具体源程序而言,在扫描字符串时识别出一个单词,若这个单词的类型是关键字、普通标示符、常数或界符中之一,那么就将此单词以文字说明的形式输出.每次调用词法分析程序,它均能自动继续扫描下去,形成下一个单词,直到整个源程序全部扫描完毕,从而形成相应的单词串。
输出形式例如:void $关键字流程图、程序流程图:程序:#include<string.h>#include<stdio.h>#include<stdlib.h>#include<ctype.h>//定义关键字char*Key[10]={"main","void","int","char","printf","scanf","else","if","return"}; char Word[20],ch; // 存储识别出的单词流int IsAlpha(char c) { //判断是否为字母if(((c<='z')&&(c>='a'))||((c<='Z')&&(c>='A'))) return 1;else return 0;}int IsNum(char c){ //判断是否为数字if(c>='0'&&c<='9') return 1;else return 0;}int IsKey(char *Word){ //识别关键字函数int m,i;for(i=0;i<9;i++){if((m=strcmp(Word,Key[i]))==0){if(i==0)return 2;return 1;}}return 0;}void scanner(FILE *fp){ //扫描函数char Word[20]={'\0'};char ch;int i,c;ch=fgetc(fp); //获取字符,指针fp并自动指向下一个字符if(IsAlpha(ch)){ //判断该字符是否是字母Word[0]=ch;ch=fgetc(fp);i=1;while(IsNum(ch)||IsAlpha(ch)){ //判断该字符是否是字母或数字Word[i]=ch;i++;ch=fgetc(fp);}Word[i]='\0'; //'\0' 代表字符结束(空格)fseek(fp,-1,1); //回退一个字符c=IsKey(Word); //判断是否是关键字if(c==0) printf("%s\t$普通标识符\n\n",Word);//不是关键字else if(c==2) printf("%s\t$主函数\n\n",Word);else printf("%s\t$关键字\n\n",Word); //输出关键字 }else //开始判断的字符不是字母if(IsNum(ch)){ //判断是否是数字Word[0]=ch;ch=fgetc(fp);i=1;while(IsNum(ch)){Word[i]=ch;i++;ch=fgetc(fp);}Word[i]='\0';fseek(fp,-1,1); //回退printf("%s\t$无符号实数\n\n",Word);}else //开始判断的字符不是字母也不是数字{Word[0]=ch;switch(ch){case'[':case']':case'(':case')':case'{':case'}':case',':case'"':case';':printf("%s\t$界符\n\n",Word); break;case'+':ch=fgetc(fp);Word[1]=ch;if(ch=='='){printf("%s\t$运算符\n\n",Word);//运算符“+=”}else if(ch=='+'){printf("%s\t$运算符\n\n",Word); //判断结果为“++”}else {fseek(fp,-1,1);printf("%s\t$运算符\n\n",Word); //判断结果为“+”}break;case'-':ch=fgetc(fp);Word[1]=ch;if(ch=='='){printf("%s\t$运算符\n\n",Word); }else if(ch=='-'){printf("%s\t$运算符\n\n",Word); //判断结果为“--”}else {fseek(fp,-1,1);printf("%s\t$运算符\n\n",Word); //判断结果为“-”}break;case'*':case'/':case'!':case'=':ch=fgetc(fp);if(ch=='='){printf("%s\t$运算符\n\n",Word);}else {fseek(fp,-1,1);printf("%s\t$运算符\n\n",Word);}break;case'<':ch=fgetc(fp);Word[1]=ch;if(ch=='='){printf("%s\t$运算符\n\n",Word); //判断结果为运算符“<=”}else if(ch=='<'){printf("%s\t$运算符\n\n",Word); //判断结果为“<<”}else {fseek(fp,-1,1);printf("%s\t$运算符\n\n",Word); //判断结果为“<”}break;case'>':ch=fgetc(fp);Word[1]=ch;if(ch=='=') printf("%s\t$运算符\n\n",Word);else {fseek(fp,-1,1);printf("%s\t$运算符\n\n",Word);}break;case'%':ch=fgetc(fp);Word[1]=ch;if(ch=='='){printf("%s\t$运算符\n\n",Word);}if(IsAlpha(ch)) printf("%s\t$类型标识符\n\n",Word);else {fseek(fp,-1,1);printf("%s\t$取余运算符\n\n",Word);}break;default:printf("无法识别字符!\n\n"); break;}}}main(){char in_fn[30]; //文件路径FILE *fp;printf("\n请输入源文件名(包括路径和后缀名):");while(1){gets(in_fn);//scanf("%s",in_fn);if((fp=fopen(in_fn,"r"))!=NULL) break; //读取文件内容,并返回文件指针,该指针指向文件的第一个字符else printf("文件路径错误!请重新输入:");}printf("\n******************* 词法分析结果如下 *******************\n");do{ch=fgetc(fp);if(ch=='#') break; //文件以#结尾,作为扫描结束条件else if(ch==' '||ch=='\t'||ch=='\n'){} //忽略空格,空白,和换行else{fseek(fp,-1,1); //回退一个字节开始识别单词流scanner(fp);}}while(ch!='#');return(0);}4.实验结果解析源文件:void main(){int a=3;a+=b;printf("%d",a);return;}#解析结果:5.实验总结分析通过本次实验,让再次浏览了有关c语言的一些基本知识,特别是对文件,字符串进行基本操作的方法。
中文分词实验
中文分词实验一、实验目的:目的:了解并掌握基于匹配的分词方法,以及分词效果的评价方法。
实验要求:1、从互联网上查找并构建不低于10万词的词典,构建词典的存储结构;2、选择实现一种机械分词方法(双向最大匹配、双向最小匹配、正向减字最大匹配法等)。
3、在不低于1000个文本文件,每个文件大于1000字的文档中进行中文分词测试,记录并分析所选分词算法的准确率、分词速度。
预期效果:1、平均准确率达到85%以上二、实验方案:1.实验平台系统:win10软件平台:spyder语言:python2.算法选择选择正向减字最大匹配法,参照《搜索引擎-原理、技术与系统》教材第62页的描述,使用python语言在spyder软件环境下完成代码的编辑。
算法流程图:Figure 错误!未指定顺序。
. 正向减字最大匹配算法流程Figure 错误!未指定顺序。
. 切词算法流程算法伪代码描述:3.实验步骤1)在网上查找语料和词典文本文件;2)思考并编写代码构建词典存储结构;3)编写代码将语料分割为1500个文本文件,每个文件的字数大于1000字;4)编写分词代码;5)思考并编写代码将语料标注为可计算准确率的文本;6)对测试集和分词结果集进行合并;7)对分词结果进行统计,计算准确率,召回率及F值(正确率和召回率的调和平均值);8)思考总结,分析结论。
4.实验实施我进行了两轮实验,第一轮实验效果比较差,于是仔细思考了原因,进行了第二轮实验,修改参数,代码,重新分词以及计算准确率,效果一下子提升了很多。
实验过程:(1)语料来源:语料来自SIGHAN的官方主页(/),SIGHAN是国际计算语言学会(ACL)中文语言处理小组的简称,其英文全称为“Special Interest Group forChinese Language Processing of the Association for ComputationalLinguistics”,又可以理解为“SIG汉“或“SIG漢“。
中科院中文分词系统调研报告
自然语言处理调研报告(课程论文、课程设计)题目:最大正向匹配中文分词系统作者:陈炳宏吕荣昌靳蒲王聪祯孙长智所在学院:信息科学与工程学院专业年级:信息安全14-1指导教师:努尔布力职称:副教授2016年10月29日目录一、研究背景、目的及意义 (3)二、研究内容和目标 (4)三、算法实现 (5)四、源代码 (7)1.seg.java 主函数 (7)2. dict.txt 程序调用的字典 (10)3.实验案例 (11)五、小结 (12)一、研究背景、目的及意义中文分词一直都是中文自然语言处理领域的基础研究。
目前,网络上流行的很多中文分词软件都可以在付出较少的代价的同时,具备较高的正确率。
而且不少中文分词软件支持Lucene扩展。
但不过如何实现,目前而言的分词系统绝大多数都是基于中文词典的匹配算法。
在这里我想介绍一下中文分词的一个最基础算法:最大匹配算法(Maximum Matching,以下简称MM算法) 。
MM算法有两种:一种正向最大匹配,一种逆向最大匹配。
二、研究内容和目标1、了解、熟悉中科院中文分词系统。
2、设计程序实现正向最大匹配算法。
3、利用正向最大匹配算法输入例句进行分词,输出分词后的结果。
三、算法实现图一:算法实现正向最大匹配算法:从左到右将待分词文本中的几个连续字符与词表匹配,如果匹配上,则切分出一个词。
但这里有一个问题:要做到最大匹配,并不是第一次匹配到就可以切分的。
算法示例:待分词文本: content[]={"中","华","民","族","从","此","站","起","来","了","。
"}词表: dict[]={"中华", "中华民族" , "从此","站起来"}(1) 从content[1]开始,当扫描到content[2]的时候,发现"中华"已经在词表dict[]中了。
中文分词实验报告
实验:中文分词实验小组成员:黄婷苏亮肖方定山一、实验目的:1.实验目的(1)了解并掌握基于匹配的分词方法、改进方法、分词效果的评价方法等2.实验要求(1)从互联网上查找并构建不低于10万词的词典,构建词典的存储结构;(2)选择实现一种机械分词方法(双向最大匹配、双向最小匹配、正向减字最大匹配法等),同时实现至少一种改进算法。
(3)在不低于1000个文本文件(可以使用附件提供的语料),每个文件大于1000字的文档中进行中文分词测试,记录并分析所选分词算法的准确率、召回率、F-值、分词速度。
二、实验方案:1. 实验环境系统:win10软件平台:spyder语言:python2. 算法选择(1)选择正向减字最大匹配法(2)算法伪代码描述:3. 实验步骤● 在网上查找语料和词典文本文件; ● 思考并编写代码构建词典存储结构;●编写代码将语料分割为1500 个文本文件,每个文件的字数大于1000 字;●编写分词代码;●思考并编写代码将语料标注为可计算准确率的文本;●对测试集和分词结果集进行合并;●对分词结果进行统计,计算准确率,召回率及 F 值(正确率和召回率的调和平均值);●思考总结,分析结论。
4. 实验实施实验过程:(1)语料来源:语料来自SIGHAN 的官方主页(/ ),SIGHAN 是国际计算语言学会(ACL )中文语言处理小组的简称,其英文全称为“Special Interest Group for Chinese Language Processing of the Association for Computational Linguistics”,又可以理解为“SIG 汉“或“SIG 漢“。
SIGHAN 为我们提供了一个非商业使用(non-commercial )的免费分词语料库获取途径。
我下载的是Bakeoff 2005 的中文语料。
有86925 行,2368390 个词语。
语料形式:“没有孩子的世界是寂寞的,没有老人的世界是寒冷的。
实验一、词法分析器(含源代码)
词法分析器实验报告一、实验目的及要求本次实验通过用C语言设计、编制、调试一个词法分析子程序,识别单词,实现一个C语言词法分析器,经过此过程可以加深对编译器解析单词流的过程的了解。
运行环境:硬件:win dows xp软件:visual C++6.0二、实验步骤1.查询资料,了解词法分析器的工作过程与原理。
2.分析题目,整理出基本设计思路。
3.实践编码,将设计思想转换用c语言编码实现,编译运行。
4.测试功能,多次设置包含不同字符,关键字的待解析文件,仔细察看运行结果,检测该分析器的分析结果是否正确。
通过最终的测试发现问题,逐渐完善代码中设置的分析对象与关键字表,拓宽分析范围提咼分析能力。
三、实验内容本实验中将c语言单词符号分成了四类:关键字key (特别的将main说明为主函数)、普通标示符、常数和界符。
将关键字初始化在一个字符型指针数组*key[]中,将界符分别由程序中的case列出。
在词法分析过程中,关键字表和case列出的界符的内容是固定不变的(由程序中的初始化确定),因此,从源文件字符串中识别出现的关键字,界符只能从其中选取。
标识符、常数是在分析过程中不断形成的。
对于一个具体源程序而言,在扫描字符串时识别出一个单词,若这个单词的类型是关键字、普通标示符、常数或界符中之一,那么就将此单词以文字说明的形式输出.每次调用词法分析程序,它均能自动继续扫描下去,形成下一个单词,直到整个源程序全部扫描完毕,从而形成相应的单词串。
输出形式例如:void $ 关键字流程图、程序流程图:开始\ .丿输入源文件路径+■路径是否效是回退初始化文件指针.识别指针内容文件结束?否跳过该字符指向下一字符指向下一字符是字母惑数字nn将字符加入字符数组Word[]是是是数字吗丫否输出word为常数将字符加入字符数组Word[]将字符加入字符数组Word[]输出word为界符输出Word内容为不可识别指向下一字符4程序:#in clude<stri ng.h>#in clude<stdio.h>#in clude<stdlib.h>#in clude<ctype.h>// 定义关键字char*Key[10]={"mai n","void","i nt","char","pri ntf',"sca nf',"else","if","return"}; char Word[20],ch; // 存储识别出的单词流int lsAlpha(char c) { // 判断是否为字母if(((c<='z') &&(c>='a'))||((c<='Z')&&(c>='A'))) return 1;else return 0;}int IsNum(char c){ // 判断是否为数字if(c>='0'&&c<='9') return 1;else return 0;}int IsKey(char *Word){ // 识别关键字函数int m,i;for(i=0;i<9;i++){if((m=strcmp(Word,Key[i]))==0){if(i==0)return 2;return 1;}}return 0;}void scann er(FILE *fp){ //char Word[20]={'\0'};char ch;int i,c;ch=fgetc(fp); // if(IsAlpha(ch)){ //Word[0]=ch; ch=fgetc(fp);扫描函数获取字符,指针fp并自动指向下一个字符判断该字符是否是字母i=1;while(lsNum(ch)||lsAlpha(ch)){ // 判断该字符是否是字母或数字Word[i]=ch; i++; ch=fgetc(fp); }Word[i]='\0: 〃'\0'fseek(fp,-1,1); c=lsKey(Word); if(c==0) prin tf("%s\t$ elseif(c==2) prin tf("%s\t$ else prin tf("%s\t$Word[0]=ch; ch=fgetc(fp);i=1; while(IsNum(ch)){Word[i]=ch; i++; ch=fgetc(fp); }Word[i]='\0'; fseek(fp,-1,1); // 回退printf("%s\t$无符号实数 \n\n ”,Word);}else // 开始判断的字符不是字母也不是数字{Word[0]=ch; switch(ch){ case'[': case']': case'(': case')': case'{': case'}': case',': case'"':case';':pri ntf("%s\t$ 界符 \n\n". Word); break;case'+':ch=fgetc(fp);Word[1]=ch; if(ch=='='){代表字符结束(空格) //回退一个字符 //判断是否是关键字 普通标识符\n\n",Word);//不是关键字主函数 \n\n",Word); 关键字\n\n",Word); //输出关键字 } else//开始判断的字符不是字母if(IsNum(ch)){//判断是否是数字case'*': case'/': case'!':case'=':ch=fgetc(fp);if(ch=='='){printf("%s\t$ 运算符 \n\n",Word); } else { fseek(fp,-1,1);printf("%s\t$ 运算符 \n\n",Word); } break;case'<':ch=fgetc(fp);Word[1]=ch; if(ch=='='){printf("%s\t$ 运算符\n\n",Word); // 判断结果为运算符 }else if(ch=='<'){ printf("%s\t$ 运算符 \n\n",Word); //判断结果为“ <<”}else {prin tf("%s\t$ } elseif(ch=='+'){ prin tf("%s\t$ } else { fseek(fp,-1,1); prin tf("%s\t$ } break;case'-':ch=fgetc(fp);Word[1]=ch; if(ch=='='){ prin tf("%s\t$ else if(ch=='-'){ prin tf("%s\t$ } else { fseek(fp,-1,1); prin tf("%s\t$ } break;运算符\n\n",Word);〃运算符 \n\n",Word); //运算符 \n\n",Word); //运算符 \n\n",Word);运算符 \n\n",Word); //运算符“ +=”判断结果为“ ++”判断结果为“ +”}判断结果为“--”判断结果为“-”<=”fseek(fp,-1,1); printf("%s\t$运算符 \n\n",Word); // 判断结果为“ <”} break;case'>':ch=fgetc(fp);Word[1]=ch;if(ch=='=') pri ntf("%s\t$ else {fseek(fp,-1,1); printf("%s\t$ 运算符 \n\n",Word);} break;case'%':ch=fgetc(fp);Word[1]=ch; if(ch=='='){printf("%s\t$ if(lsAlpha(ch)) prin tf("%s\t$ else {fseek(fp,-1,1); printf("%s\t$ 取余运算符 \n\n",Word); } break;default:pri ntf(" }mai n() {// char in_fn[30]; FILE *fp; prin tf("\n while(1){gets(in_fn); //scan f("%s",in_fn); if((fp=fope n(in_fn,"r"))!=NULL) break; // 指针指向文件的第一个字符 else prin tf(" 文件路径错误 } printf("\n*******************do{ ch=fgetc(fp);if(ch=='#') break; // else if(ch==' '||ch=='\t'||ch=='\n'){} // else{请输入源文件名 (包括路径和后缀名)!请重新输入:"); 词法分析结果如下 文件路径读取文件内容,并返回文件指针,该 *******************\n")・ 文件以#结尾,作为扫描结束条件 忽略空格,空白,和换行运算符 \n\n",Word);运算符 \n\n",Word);}类型标识符\n\n",Word);无法识别字符!\n\n"); break;fseek(fp,-1,1); // 回退一个字节开始识别单词流sea nn er(fp);}}while(ch!='#'); return(O);}4.实验结果解析源文件:void mai n(){int a=3;a+=b;prin tf("%d",a);return;}#解析结果:5•实验总结分析通过本次实验,让再次浏览了有关c语言的一些基本知识,特别是对文件,字符串进行基本操作的方法。
实验1 中文分词实验
实验内容
• 请分别使用正向最大匹配算法和逆向最大匹配 算法及给定的字典对以下句子进行分词,并分 别显示结果:
一把青菜 幼儿园地节目
实验一作业
• 请选择以下任意一个完成:
1.请使用双向匹配算法对给定测试文本进行分词:
• 给定测试文本为:实验1作业测试文本.txt • 词典为:chineseDic.txt • 要求:编程实现,并计算分词的P, R,F值和分词时间。
2.请使用概率最大方法及给定语料库对以下句子分词:
• “对外经济技术合作与交流不断扩大。” • 要求:利用人民日报语料库来计算每个候选词的概率值及 最佳左邻词,及分词结果。并计算分词的P,R,F值和分词 时间。
注意作业完成时间:
2周,请在第4周上课前提交,4人以内小组提交。 最好是C++或JAVA 报告标题、理论描述、算法描述、详例描述、软件演 示图, 请看样板
• 详例描述:
以“一把青菜”为例,详细描述算法如下
将程序实现的截图粘贴过来
• 软件演示:
另外,请每个小组将每次的作业实现在同一个软件平台中,班级及 成员不要变化,这样学期结束,就实现了一个NLP的工具集,最后 添加一个应用就是你的大作业了。
• 语言可以任意:
• 作业以程序软件+报告的格式,要求:
• 作业提交格式:
作业内容放置一个文件夹中,并压缩交给我 文件夹命名:实验一+班级+姓名.rar
实验报告1 双向匹配中文分词 • 理论描述:
中文分词是。。。。,
• 算法描述:
本文实现双向匹配算法,具体算法描述如下: MM: RMM:
搜索引擎实验三
一、实验目的理解搜索引擎中的分词技术。
二、实验内容编写程序实现对一段中文文章,利用最长正匹配算法进行分词三、实验过程3.1 分词程序流程图3.2 分词程序源代码boolean f;int Dlen=33;String dictionary[]={"生命","最后","余光","仔仔细细","检视","一点","一滴","鲜明","生动","日子","熟悉","面孔","一言一语","生活","装进","装入","扉页","钟爱", "一并","自己","一遍","甘心","二十","收拾","一切","灿烂","结束","微笑","昨天","还给","孤单","留给","自己"};try {FileInputStream in=new FileInputStream("d:\\123.txt");BufferedReader breader = new BufferedReader(newInputStreamReader(in,"gb2312"));String inputstr,word=null;int i,j,k;while ((inputstr=breader.readLine())!=null){for (i=0;i<inputstr.length();){f=false;for (j=4;j>1;j--){word=inputstr.substring(i, i+j);for (k=0;k<Dlen;k++)if (dictionary[k].equals(word)){f=true;break;}if (f) break;}word=inputstr.substring(i, i+j);if (!(word.equals(",")||word.equals("。
自然语言理解实验报告
自然语言理解课程实验报告实验一、中文分词1、实验内容用最大匹配算法设计分词程序实现对文档分词,并计算该程序分词的正确率、召回率及F-测度。
实验数据:(1)wordlist.txt 词表文件(2)pku_test.txt 未经过分词的文档文件(3)pku_test_gold.txt 经过分词的文档文件2、实验所采用的开发平台及语言工具开发平台:Eclipse软件语言工具:Java语言3、实验的核心思想和算法描述核心思想:正向最大匹配算法 (Forward MM, FMM)算法描述:正向最大匹配法算法如下所示:逆向匹配法思想与正向一样,只是从右向左切分,这里举一个例子:输入例句:S1="计算语言学课程有意思" ;定义:最大词长MaxLen = 5;S2= " ";分隔符 = “/”;假设存在词表:…,计算语言学,课程,意思,…;最大逆向匹配分词算法过程如下:(1)S2="";S1不为空,从S1右边取出候选子串W="课程有意思";(2)查词表,W不在词表中,将W最左边一个字去掉,得到W="程有意思";(3)查词表,W不在词表中,将W最左边一个字去掉,得到W="有意思";(4)查词表,W不在词表中,将W最左边一个字去掉,得到W="意思"(5)查词表,“意思”在词表中,将W加入到S2中,S2=" 意思/",并将W 从S1中去掉,此时S1="计算语言学课程有";(6)S1不为空,于是从S1左边取出候选子串W="言学课程有";(7)查词表,W不在词表中,将W最左边一个字去掉,得到W="学课程有";(8)查词表,W不在词表中,将W最左边一个字去掉,得到W="课程有";(9)查词表,W不在词表中,将W最左边一个字去掉,得到W="程有";(10)查词表,W不在词表中,将W最左边一个字去掉,得到W="有",这W 是单字,将W加入到S2中,S2=“ /有 /意思”,并将W从S1中去掉,此时S1="计算语言学课程";(11)S1不为空,于是从S1左边取出候选子串W="语言学课程";(12)查词表,W不在词表中,将W最左边一个字去掉,得到W="言学课程";(13)查词表,W不在词表中,将W最左边一个字去掉,得到W="学课程";(14)查词表,W不在词表中,将W最左边一个字去掉,得到W="课程";(15)查词表,“意思”在词表中,将W加入到S2中,S2=“课程/ 有/ 意思/”,并将W从S1中去掉,此时S1="计算语言学";(16)S1不为空,于是从S1左边取出候选子串W="计算语言学";(17)查词表,“计算语言学”在词表中,将W加入到S2中,S2=“计算语言学/ 课程/ 有/ 意思/”,并将W从S1中去掉,此时S1="";(18)S1为空,输出S2作为分词结果,分词过程结束。
北大天网中文分词源码(C++版)及调试
北大天网中文分词源码(C++版)及调试周常欣 2020-3-5采用VC++6.0编译器编译源码(如果您的操作系统是win,有兼容win7操作系统的版本,若为win10则可装VS或codeblocks等编译器)一、创建VC++工程项目在编译器菜单栏左键单击“文件”,在弹出的下拉菜单选择“新建”,如上图。
弹出对话框,如下图在对话框左侧默认显示的“工程”区,选择Win Console Application(命令行应用 ),也就是说编程出的程序是“DOS界面的程序”。
在对话框右侧的“工程名称”填写Pk_Segment,如下图。
在对话框右侧的“位置”,选择工程项目的存储路径,本例为:D:\VC_CODE\Pk_Segment接下来,点击“确定”按键。
在弹出的对话框选择默认的“一个空工程”,点“完成”按钮。
一路点“确定”按钮完成工程创建。
二、创建头文件(1)创建加载词典类的C++头文件(扩展名为h)在编译器菜单栏左键单击“文件”,在弹出的下拉菜单选择“新建”,如上图。
弹出对话框,如下图在对话框左侧默认显示的“文件”区,选择C/C++ Header File(C或C++头文件 ),在对话框右侧的“文件名”填写Dict.h,如上图,接下来点击确定按钮。
*注C++的头文件扩展名为.h,源文件的扩展名为.cpp。
编译器变为如下界面。
在编译器的“代码编辑区”添加如下代码#include <iostream>#include <fstream>#include <string>#include <map>#include <cstdlib>using namespace std;const string DICTFILENAME("words.dict"); //定义词典路径class CDictpublic:CDict();~CDict(); //虑析构函数bool GetFreq(string&) const {return false;};bool IsWord(string&) const;void AddFreq(string&) {};private:map<string, int> mapDict;void OpenDict();};然后在编辑器菜单栏点击“保存”的快捷菜单图标。
中文分词代码
中文分词代码private void button1_Click(object sender, EventArgs e){StringBuilder sb = new StringBuilder();sb.Remove(0, sb.Length);string t1 = "";int i = 0;Analyzer analyzer = new Lucene.China.ChineseAnalyzer();StringReader sr = new StringReader(richTextBox1.Text);TokenStream stream = analyzer.TokenStream(null, sr);long begin = System.DateTime.Now.Ticks;Token t = stream.Next();while (t != null){t1 = t.ToString(); //显示格式:(关键词,0,2) ,需要处理t1 = t1.Replace("(","");char[] separator = { ',' };t1 = t1.Split(separator)[0];sb.Append(i+":"+ t1 + "\r\n");t = stream.Next();i++;}richTextBox2.T ext = sb.ToString();long end = System.DateTime.Now.Ticks; //100毫微秒int time = (int)((end - begin) / 10000); //msrichTextBox2.T ext += "耗时" + (time) + "ms \r\n=================================\r\n";}三、程序具体程序如下(程序中包含权重,插入次数等要素,目前的算法并没有利用这些.可以借此写出更有效的分词算法):> 纯文本方式> 拷贝到裁剪板> 打印1.public struct ChineseWordUnit2.{3.private string _word;4.private int _power;5./// <summary>6./// 中文词语单元所对应的中文词。
实验1 中文分词实验
• 语பைடு நூலகம்可以任意:
• 作业以程序软件+报告的格式,要求:
• 作业提交格式:
作业内容放置一个文件夹中,并压缩交给我 文件夹命名:实验一+班级+姓名.rar
实验报告1 双向匹配中文分词 • 理论描述:
中文分词是。。。。,
• 算法描述:
本文实现双向匹配算法,具体算法描述如下: MM: RMM:
• 详例描述:
以“一把青菜”为例,详细描述算法如下
将程序实现的截图粘贴过来
• 软件演示:
另外,请每个小组将每次的作业实现在同一个软件平台中,班级及 成员不要变化,这样学期结束,就实现了一个NLP的工具集,最后 添加一个应用就是你的大作业了。
2.请使用概率最大方法及给定语料库对以下句子分词:
• “对外经济技术合作与交流不断扩大。” • 要求:利用人民日报语料库来计算每个候选词的概率值及 最佳左邻词,及分词结果。并计算分词的P,R,F值和分词 时间。
注意作业提交要求:看后一个PPT
作业提交要求
• 作业完成时间:
2周,请在第4周上课前提交,4人以内小组提交。 最好是C++或JAVA 报告标题、理论描述、算法描述、详例描述、软件演 示图, 请看样板
实验一 中文分词
实验内容
• 请分别使用正向最大匹配算法和逆向最大匹配 算法及给定的字典对以下句子进行分词,并分 别显示结果:
一把青菜 幼儿园地节目
实验一作业
• 请选择以下任意一个完成:
1.请使用双向匹配算法对给定测试文本进行分词:
• 给定测试文本为:实验1作业测试文本.txt • 词典为:chineseDic.txt • 要求:编程实现,并计算分词的P, R,F值和分词时间。
实验报告代码格式
一、实验目的1. 理解文本分类的基本原理和流程。
2. 掌握Python中常用的文本处理和机器学习库的使用。
3. 实现一个简单的文本分类器,并对分类效果进行评估。
二、实验环境1. 操作系统:Windows 102. 编程语言:Python3.73. 依赖库:jieba(中文分词库)、sklearn(机器学习库)、pandas(数据处理库)三、实验内容1. 数据预处理2. 特征提取3. 模型训练4. 模型评估5. 实验结果分析四、实验步骤1. 数据预处理(1)数据获取本实验使用的是某中文论坛的评论数据,包含正面评论、负面评论和中性评论。
(2)数据清洗对数据进行去重、去除无效评论、去除停用词等操作。
(3)分词使用jieba库对评论进行分词处理。
2. 特征提取(1)TF-IDF使用sklearn库中的TfidfVectorizer对分词后的文本进行TF-IDF特征提取。
(2)词袋模型使用sklearn库中的CountVectorizer对分词后的文本进行词袋模型特征提取。
3. 模型训练(1)选择模型本实验选择支持向量机(SVM)作为分类模型。
(2)训练模型使用训练集数据对SVM模型进行训练。
4. 模型评估(1)测试集划分将数据集划分为训练集和测试集,比例为7:3。
(2)模型评估指标选择准确率、召回率、F1值等指标对模型进行评估。
5. 实验结果分析(1)准确率通过实验结果可以看出,使用TF-IDF特征提取和SVM模型在测试集上的准确率为85.3%。
(2)召回率召回率表示模型能够正确识别的正面评论数量与实际正面评论数量的比例。
实验结果显示,召回率为82.5%。
(3)F1值F1值是准确率和召回率的调和平均值,可以反映模型的综合性能。
实验结果显示,F1值为83.8%。
五、实验总结1. 本实验实现了基于Python的文本分类器,通过数据预处理、特征提取、模型训练和模型评估等步骤,成功对中文论坛评论进行了分类。
2. 实验结果表明,使用TF-IDF特征提取和SVM模型在测试集上的分类效果较好,准确率达到85.3%,召回率为82.5%,F1值为83.8%。
自然语言处理-中文分词程序实验报告(含源代码)
9
infile.open("dict/number.txt.utf8"); if (!infile.is_open()) { cerr << "Unable to open input file: " << "wordlexicon" << " -- bailing out!" << endl; exit(-1); } while (getline(infile, strtmp)) // 读入词典的每一行并将其添加入哈希中 { istringstream istr(strtmp); istr >> word; //读入每行第一个词 numberhash.insert(sipair(word, 1)); //插入到哈希中 } infile.close(); infile.open("dict/unit.txt.utf8"); if (!infile.is_open()) { cerr << "Unable to open input file: " << "wordlexicon" << " -- bailing out!" << endl; exit(-1); } while (getline(infile, strtmp)) // 读入词典的每一行并将其添加入哈希中 { istringstream istr(strtmp); istr >> word; //读入每行第一个词 unithash.insert(sipair(word, 1)); //插入到哈希中 } infile.close(); } //删除语料库中已有的分词空格,由本程序重新分词 string eat_space(string s1) { int p1=0,p2=0; int count; string s2; while(p2 < s1.length()){ //删除全角空格 // if((s1[p2]-0xffffffe3)==0 && // s1[p2+1]-0xffffff80==0 && // s1[p2+2]-0xffffff80==0){//空格
WordSegment中文分词源代码
#include "stdafx.h"#include<iostream>#include<fstream>#include<vector>#include<string>#include<stack>using namespace std;const int s1 = 0XB0,s2 = 0XA1,e1 = 0XF8,e2 = 0XFF; const int maxwordlen = 50;struct Second{string key;Second *next;Second(string k = "",Second *n = 0):key(k),next(n){} };struct Head{int size;string key;vector<Second*> W;Head(string k = "",int s = 0):key(k),size(s){}};class Dictiory{vector<Head> H;ifstream fin;ifstream fcin;ofstream fout;int hash[e1 - s1][e2 - s2];int BinarySearch(string str,int k);int GetNum();void LoadDic();bool IsC(char c);bool IsEc(char c);void AddWord(string str,int k);void InsertWord(string str,int k);bool IsWord(string str,int k,int t);void SkipNotChinese(string &str,stack<string> &stk);public:Dictiory(string sfilename,string dfilename);void SegmentWord(string s);void PrintDic(){for(int i = 0; i < e1 - s1;i++)for(int j = 0; j < e2 - s2;j++){if(hash[i][j] >= 0){fout << H[hash[i][j]].key << endl;for(int k = 0; k < H[hash[i][j]].W.size() ;k++){Second *t = H[hash[i][j]].W[k];while(t){fout << H[hash[i][j]].key;fout << t->key << endl;t = t->next;}}}fout << endl;}}};Dictiory::Dictiory(string sfilename,string dfilename){int i,j;for(i = 0; i < e1 - s1;i++)for(j = 0; j < e2 - s2;j++)hash[i][j] = -1;H.resize(6768);fin.open(sfilename.c_str());fout.open(dfilename.c_str());LoadDic();}int Dictiory::BinarySearch(string str,int k){int len = str.length();int L = 0,R = H[k].W.size() - 1,M;while(L <= R){M = (L + R)/2;if(H[k].W[M]->key.size() == len)return M;else if(H[k].W[M]->key.size() < len)L = M + 1;else R = M - 1;}return -1;}void Dictiory::AddWord(string str,int k){if(str.length() > H[k].size){H[k].size = str.length();Second *t = new Second(str);H[k].W.push_back(t);}elseInsertWord(str,k);}void Dictiory::InsertWord(string str,int k){int in = BinarySearch(str,k);if(in == -1){int L = 0,R = H[k].W.size() - 1;int len = str.length();while(L <= R&&len > H[k].W[L]->key.size())L++;H[k].W.resize(H[k].W.size() + 1);for(int i = R + 1;i > L;i--)H[k].W[i] = H[k].W[i - 1];Second *t = new Second(str);H[k].W[L] = t;}else{Second *pre,*t = H[k].W[in];while(t){pre = t;t = t->next;}pre->next = new Second(str);}}int Dictiory::GetNum(){char cstr[maxwordlen];fin.getline(cstr,maxwordlen);int n = 0,i;for(i = 0; i < strlen(cstr);i++)n = n * 10 + cstr[i] - '0';return n;}void Dictiory::LoadDic(){char cstr[maxwordlen];string str;int i,j,k = 0,wordnumber;while(fin.getline(cstr,maxwordlen)){i = (unsigned char)cstr[0] - s1;j = (unsigned char)cstr[1] - s2;hash[i][j] = k;H[k].key = cstr;wordnumber = GetNum();for(i = 0; i < wordnumber;i++){fin.getline(cstr,maxwordlen);str = cstr;str = str.substr(2,str.length() - 2);AddWord(str,k);}k++;}}bool Dictiory::IsC(char c){unsigned value = unsigned((unsigned char)c);return value >= s1&&value < e1;}bool Dictiory::IsEc(char c){unsigned value = unsigned((unsigned char)c);return value <= 0X7F;}bool Dictiory::IsWord(string str,int k,int t){Second *temp = H[k].W[t];while(temp){if(temp->key == str)return true;temp = temp->next;}return false;}void Dictiory::SkipNotChinese(string &str,stack<string> &stk) {unsigned L = 0,R = str.length();while(L < R&&!IsC(str[L])){if(!IsEc(str[L]))L++;L++;}if(L > 0){stk.push(str.substr(0,L));str = str.substr(L,R - L);}}void Dictiory::SegmentWord(string s){stack<string> stk;fcin.open(s.c_str());char cstr[maxwordlen];string str,sstr;int i,j,startpos,endpos;char c;while(fcin.read(&c,sizeof(char))){if(!IsC(c)){if(!str.empty()){cout << str << " " << str.length() << endl;startpos = 0,endpos = str.length();while(startpos < endpos){if(str.length() <= 2){stk.push(str);if(!sstr.empty()){str = sstr;sstr.clear();}startpos += 2;}else{i = (unsigned char)str[0] - s1,j = (unsigned char)str[1] - s2;if(hash[i][j] >= 0){string word = str.substr(2,str.length() - 2);int in = BinarySearch(word,hash[i][j]);if((in != -1)&&IsWord(word,hash[i][j],in)){stk.push(H[hash[i][j]].key + word);startpos += str.length();str = sstr;sstr.clear();}else{sstr = sstr + str.substr(0,2);str = str.substr(2,str.length() - 2);}}else{sstr = sstr + str.substr(0,2);str = str.substr(2,str.length() - 2);}}}while(!stk.empty()){fout << stk.top() << endl;stk.pop();}}str.clear();str += c;while(fcin.read(&c,sizeof(char))&&!IsC(c))str += c;fout << str << endl;cout << str << " " << str.length() << endl;str.clear();str += c;fcin.read(&c,sizeof(char));str += c;}else{str += c;fcin.read(&c,sizeof(char));str += c;}}}int main(){Dictiory D("dictiory.txt","data.txt");//D.PrintDic();D.SegmentWord("sou.txt");system("pause");return 0;}。
中文分词处理源代码C++
#include <fstream>#include <vector>#include <string>#include <iostream>using namespace std;const int START1 = 0XB0,START2 = 0XA1, END1 = 0XF8,END2 = 0XFF; const int MAXWORDLEN = 48;ifstream fin("segdict.txt");ofstream out("out1.txt");//--------------------- 建树部分----------------------struct Node3{string S;bool IsWord;Node3 *L,*R;Node3(string s = "",bool isWord = 0, Node3 *l = 0, Node3 *r = 0):S(s),IsWord(isWord),L(l),R(r){}};struct Node2{string S;bool IsWord;Node3 *Child;Node2(string s ="",bool isWord = 0, Node3* child =0):S(s),IsWord(isWord),Child(child){}};struct Node{string S;vector<Node2>v;};vector<Node>Dic;int HASH[END1 - START1][END2 - START2];void Begin() //初始化{for (int i = 0; i < END1- START1; i++)for (int j = 0;j < END2 - START2; j++)HASH[i][j] = -1;}void BuildTree(string s, Node3 *child){int len = s.length();string t = s.substr(0,2);Node3 *LAST = child;if (child == 0)LAST = child = new Node3(t, (len == 2),0,0);else{while (LAST->L != 0)LAST = LAST->L;if (LAST->S != t){LAST->L = new Node3(t,(len == 2),0, 0);LAST = LAST->L;}}if (len > 2)BuildTree(s.substr(2,MAXWORDLEN),LAST->R); }void Dictionary() //构造整个结构{Begin();string s;int N,k = 0;while(fin >> s){Node n;n.S = s.substr(0,2);int m1 = (unsigned char)s[0] - START1;int m2 = (unsigned char)s[1] - START2;HASH[m1][m2] = k++;out << s << " " << HASH[m1][m2] << endl;fin >> N;out << N << endl;for (int i = 0; i < N; i++){fin >> s;out << s << endl;string t = s.substr(2,2);int LEN = s.length();int SIZE = n.v.size();int Len = s.length();if (SIZE == 0 ||(SIZE > 0 && n.v[SIZE-1].S != t))n.v.push_back(Node2(t, (Len == 4),0));SIZE = n.v.size();if (Len > 4)BuildTree(s.substr(4,MAXWORDLEN),n.v[SIZE-1].Child);}Dic.push_back(n);}out << "END HASH" << endl << endl;}//------------------查询部分---------------------vector<string>Dest;int BinarySearch(int x, string Sec)//二分查找第二个字{int L = 0,R = Dic[x].v.size() - 1;while (L <= R){int mid = (L + R) >> 1;if (Dic[x].v[mid].S == Sec)return mid;else if (Dic[x].v[mid].S < Sec)L = mid + 1;else R = mid - 1;}return -1;}Node3* RemainSearch(Node3*p, string cc) //顺序查找剩下的字{while (p != 0){if (p->S == cc)return p;elsep = p->L;}return 0;}unsigned CharToInt(char c){return unsigned((unsigned char)c) ;}bool IsCC(char c){unsigned val= CharToInt(c);return val >= START1 && val < END1;}bool IsEC(char c){unsigned val= CharToInt(c);return val < 0x80;}void FindNum(string src, vector<string>&dest, int &StarPos,int &EndPos) {int Strlen = src.length();while (EndPos < Strlen && !IsCC(src[EndPos])){if(!IsCC(EndPos))EndPos++;EndPos++;}if (EndPos > StarPos){dest.push_back(src.substr(StarPos,EndPos-StarPos));StarPos = EndPos;}}void Segment(string src, vector<string>&dest){int StrLen = src.length();int StartPos = 0, EndPos;while (StartPos < StrLen){EndPos = StartPos;FindNum(src,dest,StartPos,EndPos);if (StartPos >= StrLen) return ;unsigned SegLen = 2;string HeadCC = src.substr(StartPos, 2);cout <<HeadCC <<endl << endl;int m1 = (unsigned char)HeadCC[0]-START1;int m2 = (unsigned char)HeadCC[1]-START2;int HeadIndex = HASH[m1][m2];if (HeadIndex >= 0);{string SecCC = src.substr(StartPos + 2,2);if (SecCC.length() > 0 && IsCC(SecCC[0])){int B2 = BinarySearch(HeadIndex,SecCC);if (B2>=0){if (Dic[HeadIndex].v[B2].IsWord)SegLen += 2;EndPos = StartPos + 4;Node3 *p = Dic[HeadIndex].v[B2].Child;while(EndPos < StrLen && (p = RemainSearch(p,src.substr(EndPos,2)))!= 0){EndPos+= 2;if (p->IsWord)SegLen = EndPos - StartPos;p = p->R;}}}}dest.push_back(src.substr(StartPos,SegLen));StartPos += SegLen;}}int main(){Dictionary();ofstream out2("out2.txt");// string SS ="有时,我会抬头,看一看这喧嚣的人群,有没有我想见得身影,若是有那身影,或许我会看着她,看她慢慢的融入人群,直到不见。
中文分词程序实验报告
汉语分词程序实验报告一、程序功能描述:本程序每次处理时都用缓冲区的数据从头开始去存储语料库的链表中匹配一个最长的词语来输出,如若没有匹配到的词语则单独输出该首字。
为了简化程序所以语料库和预备分词文章都统一采用ASCII码的编码方式,并且不允许文中出现英语单字节编码。
别且本程序没有对未登录词和未声明数据结构格式进行处理,都按照普通汉字进行了分词,因此在最后的性能比较中这部分的准确率很差,但是在语料库有存储的部分中都是用最长匹配原则进行了分词,准确率还是达到了很高的水平。
分词符采用//+空格的方式来标记分词。
语料库的名字默认为:语料库.txt,打开方式为只读读取的文件名字默认为:resource.txt,打开方式为只读输出的文件名字默认为:result.txt,打开方式默认为追加的方式二、算法思路:(1)、从文件中读取语料库存储在内存中,组织成单链表的存储方式(2)、组织以首字的ASCII码为下标的哈希表指向语料库链表(3)、从文件中读满输入缓冲区,以缓冲区的首字的ASCII码做为下标从哈希表中查找首字相同的内存地址。
(4)、从该地址开始逐条匹配,记录其中匹配最长的词语的长度和地址。
写入文件中并写入分词符。
(5)、读满缓冲区,若文件已经读取完毕则查看缓冲区是否用尽,若已经用完则执行第(6)步,否则重复(4)过程。
(6)、释放申请的内存空间,程序结束。
三、数据结构:typedef struct coredict{//使用链表来存储语料库char data[9];struct coredict*nextPtr;}CoreDict,*CoreDictPtr;CoreDictPtr tablePtr=NULL,tailPtr=NULL,newPtr;//指向语料库链表的头和尾CoreDictPtr Hash[65536]={NULL};//一个以匹配词语的第一个字的ASCII码为下标的指向链表的哈希表int MatchLength=0;//在一个单词匹配过程中用来记录能够匹配到的最长的词语的长度CoreDictPtr MatchPtr=NULL;//在一个单词匹配过程中用来记录能够匹配到的最长的词语在链表中的地址四、函数功能:int IsEqual(char[],char[]);//判断两个汉字是否相等int LongMatch(char[],char[]);//void read(char[],FILE*);//将读入缓冲区读满void setoff(char[],int);//将已经匹配好的词语从缓冲区中删除五、性能对比分析:结果分析程序性能描述:在语义的判别和歧义消除方法只是用最长匹配法来降低误差,因此这部分的性能提升不是很明显。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
下面简要介绍一下 UTF-8 格式。 前 面 提 到 的 Unicode 的 学 名 是 "Universal Multiple-Octet Coded Character Set",简称为 UCS。UCS 可以看作是"Unicode Character Set"的缩写。 UCS 只是规定如何编码,并没有规定如何传输、保存这个编码。UTF-8 是被广泛 接受的方案。UTF-8 的一个特别的好处是它与 ISO-8859-1 完全兼容。UTF 是“UCS Transformation Format”的缩写。 UTF-8 就是以 8 位为单元对 UCS 进行编码。 从 UCS-2 到 UTF-8 的编码方式如下:
二、实验环境
UBUNTU 10.05 GCC v4.4.3
三、实验材料
中文常用词词典 《人民日报》1998 年合订本
四、实验设计
一、分词策略
据我的了解,目前较为成熟的中文分词方法主要有: 1、 词典正向最大匹配法 2、 词典逆向最大匹配法 3、 基于确定文法的分词法 4、 基于统计的分词方法 一般认为,词典的逆向匹配法要优于正向匹配法。基于确定文法和基于统计的方 法作为自然语言处理的两个流派,各有千秋。
五、结果和性能分析........................................................16 分词结果示例............................................................16 性能分析................................................................ 17
* 2)数字分词
* 3)西文分词
* 4)时间分词
* 用法:
*
./segment ARTICAL
* 范例:
* ./segment 1998-01-qiefen-file.txt.utf8
* 屏幕输出:
*
词典读入完毕,耗时 0.000776 s
*
分词完毕,耗时 3.18 s *
所以,就有了这个结论:汉字的 UTF-8 编码是 3 字节的。然而,语料库中出现的 字符并非都是汉字。比如半角空格、外国人名字间隔符等。如果把所有字单元都视为 3 字节,就要出错了。这是编程时必须考虑的问题。
5
程序流程图
6
7
程序源代码
/*
* segment.cpp ---- 中文分词程序
*
* 功能:1)中文词典分词(逆向最大匹配)
namespace __gnu_cxx {
template<> struct hash< std::string > {
size_t operator()( const std::string& x ) const {
return hash< const char* >()( x.c_str() ); } }; }
4
汉字编码格式:UTF-8
中文处理和英文处理的一个很大不同就在于编码格式的复杂性。常见的中文编码 格式有 GB2312,GB18030,GBK,Unicode 等等。同样的中文字符,在不同的汉字 编码格式中,可能有不同的二进制表示。因此编程做字符串匹配时,通常要求统一的
编码格式。
在 linux 下可以用 file 命令查看文本文件的编码格式。经过检查,发现老师提供的 词典和语料属于不同的编码格式,直接做字符串匹配可能会有问题。考虑到 UBUNTU 以 UTF-8 作为默认编码格式,我索性使用 enconv 命令将词典和语料都转换成 UTF-8 格式。
二、程序设计.............................................................4 查找算法:哈希表查找.................................................4 汉字编码格式:UTF-8...................................................5 程序流程图............................................................ 6 程序源代码............................................................ 8
二、程序设计
查找算法:哈希表查找
除了分词结果的准确性,程序的性能也是至关重要的。由于本程序采用了词典法 来分词,执行过程需要检索大量数据,因此查找效率成为程序性能的决定性因素。
据我的了解,目前比较成熟的查找算法主要有顺序查找、二分查找、哈希表查找等。 顺序查找的算法复杂度为 O(n); 二分查找的算法复杂度为 O(logn),但需要事先排序; 哈希表查找的复杂度为 O(1)。 本程序采用效率最高的哈希表查找算法。
基于确定文法的分词法
基于确定文法的分词法可以进行数字、西文、时间的分词,设计思路是这样的: 1、 增加一个词典,存储中文编码(全角)的大小写拉丁字母、中文小写数字、阿 拉伯数字、数字单位(百、千、万、亿、兆)、小数点、百分号、除号;词类型记为[D1]; 2、 增加一个词典,存储中文编码的时间单位,包括年、月、日、时、分、秒、点;词 类型记为[D2]; 3、 文法的正则表达式为[D1]*[D2]?。
* 分词结果保存在 result.txt.utf8 中。
*
* 注意:1)本程序只能处理 utf-8 文本,其他格式的文本请用 iconv 或 enconv 转换成
utf-8 格式。
* 2)程序运行需要
dict/CoreDict.txt.utf8,dict/number.txt.utf8,dict/unit.txt.utf8 三个文件。
#define MaxWordLength 12 // 最大词长字节(即 4 个汉字)
8
#define Separator " " #define UTF8_CN_LEN 3
// 词界标记 // 汉字的 UTF-8 编码为 3 字节
using namespace std; using namespace __gnu_cxx;
北京邮电大学计算机学院 《自然语言处理导论》 中文分词实验报告
姓 名: 许伟林 学 号: 08211306 指导教师: 郑岩 日 期: 2010/12/22
1
内容目录
一、实验目的............................................................... 3 二、实验环境............................................................... 3 三、实验材料............................................................... 3 四、实验设计............................................................... 3
9
infile.open("dict/number.txt.utf8"); if (!infile.is_open()) {
cerr << "Unable to open input file: " << "wordlexicon" << " -- bailing out!" << endl; exit(-1); } while (getline(infile, strtmp)) // 读入词典的每一行并将其添加入哈希中 { istringstream istr(strtmp); istr >> word; //读入每行第一个词 numberhash.insert(sipair(word, 1)); //插入到哈希中 } infile.close();
hash_map<string, int> wordhash; // 词典 hash_map<string, int> numberhash;// 数字和字母 hash_map<string, int> unithash;// 时间单位
//读入词典,以及数字、字母、时间单位集 void get_dict(void) {
3
由于时间仓促,且水平有限,本程序只实现了第 2 种和第 3 种分词法,即词典逆 向最大匹配法和基于确定文法的分词法。
词典逆向最大匹配法
词典逆向最大匹配法完成分词的大部分工作,设计思路是这样的: 1、 将词典的每个词条读入内存,最长是 4 字词,最短是 1 字词; 2、 从语料中读入一段(一行)文字,保存为字符串; 3、 如果字符串长度大于 4 个中文字符,则取字符串最右边的 4 个中文字符,作 为候选词;否则取出整个字符串作为候选词; 4、 在词典中查找这个候选词,如果查找失败,则去掉这个候选词的最左字,重 复这步进行查找,直到候选词为 1 个中文字符; 5、 将候选词从字符串中取出、删除,回到第 3 步直到字符串为空; 6、 回到第 2 步直到语料已读完。
六、有待解决的问题........................................................18 七、实验总结.............................................................. 19
2
一、实验目的
了解中文分词的意义 掌握中文分词的基本方法
string strtmp; //读取词典的每一行 string word; //保存每个词 typedef pair<string, int> sipair;