⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 myfileapp.cpp

📁 这个软件对文本文档进行预处理
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#include "stdafx.h"
#include "TextPreProcessing.h"
#include "MyFileApp.h"
#include "stdlib.h"

#include "io.h"          // 包含 _findfirst(), _findnext()函数原型
#include "direct.h"      // 包含 _chdir()函数原型
#include "errno.h"       // 包含系统变量errno

# define e_puncture1 ".!?:;"  // 西文句末标点
# define e_puncture2 "')\042" // 西文右匹配标点括号,单引号,双引号

//# define c_puncture1 "。 ! ? : ; …" // 中文句末标点
# define c_puncture1 "。 ! ? ; …" // 中文句末标点,不包含冒号
# define c_puncture2 "” ’ )"       // 中文右匹配标点

# define MAXSENT 3000 // 一个文件中最大句子数为3000
//# define MAXSENTLENGTH 2000 // 一个句子最长不超过2000字节

struct SentLengthFreq  // 定义一个结构,存放句子长度和频度信息
	{
		int SentLength;
		int SentFreq;
	};

struct Sent_Length  // 定义一个结构,存放句子本身和句子长度信息
	{
		int SLength; 
//		char Sent[MAXSENTLENGTH];
		CString Sent;
	};

////////////////////////////////////////////////////
////////////////////////////////////////////////////
////////// 公共函数

void CountLinesInAFile (CString fname)
{// 计算一个文件的行数
	FILE * in;
	CString msg;

	in = fopen((const char *) fname, "rb");
	if(!in) { AfxMessageBox("Can't open the file"); return; }

	int count = 0;
	while (!feof(in)) {
		char ch = fgetc(in);
		if(ch == '\n') count ++;
	}

	fclose (in);
	msg.Format("文件%s: 共有%d行", (const char *) fname, count);
	AfxMessageBox(msg);
}

CString ChangeFileName(CString sourceName, CString newAffix) 
{// 在原文件名后加任意字符产生新文件名,文件后缀名为txt
	int i=sourceName.ReverseFind('.'); // 从后向前搜索圆点
	int j=sourceName.ReverseFind('\\'); // 从后向前搜索反斜杠
	if (i>j) return sourceName.Left(i)+newAffix+".txt";
	else return sourceName+newAffix+".txt";
}

CString ChangeExt(CString oldName,CString newExt)
{// 将原文件名的后缀部分改为新的后缀名
	int i=oldName.ReverseFind('.');
	int j=oldName.ReverseFind('\\');
	if(i>j)
		return oldName.Left(i+1)+newExt;
	else
		return oldName+"."+newExt;
}

int charType (unsigned char *s)
{// 判断字符类型
	if (* s<128) 
		return 0;
	else 
		if (* s >= 176) 
			return 1;
		else 
			return 2;
}


int ProcessFiles(char *Ext, char * Name, void(* ProcessAFile)(CString fileName))
{
	CFileDialog dlg(TRUE, Ext, Name, OFN_ALLOWMULTISELECT);
	
	//////////////////////////////////////////////
	//// 分配一片空间存放文件名,可以选取多个文件

	CString strFileNames; 

	dlg.m_ofn.lpstrFile = strFileNames.GetBuffer(2048);
	dlg.m_ofn.nMaxFile = 2048;

	if(dlg.DoModal()!=IDOK) {
		AfxMessageBox("您没有选取任何文件!");
		return 0;
	}
	
	strFileNames.ReleaseBuffer();
	///////////////////////////////////////////////

	int fileCount = 0;
	CString FileName;
	POSITION pos = dlg.GetStartPosition(); // 获取第一个文件名的起点位置
	while(pos!=NULL) {  // 如果有文件可以获取
		FileName = dlg.GetNextPathName(pos); // 获取文件名,并移到下一个文件名的起始位置
		ProcessAFile(FileName); // 调用处理单个文件的函数
		fileCount ++; // 这里有点问题,实际上并不知道是否"真的"处理了文件,
					// 也许调用的函数打开了一个文件但不符合处理要求,
					// 根本没有处理文件
	}

	AfxMessageBox("全部文件处理完毕!");
	return fileCount; // 返回文件个数
}


////////////////////////////////////////
////////////////////////////////////////
//////// 文本预处理函数

CString RemoveSpaceOneLine(CString s)
{//去除一行中的中文和西文空格

	s.TrimLeft(); // 先把字符串左边的空格去掉
	
	CString s2="";
	
	while(!s.IsEmpty()) {
		
		CString ch=s.Left(1);
		if (ch[0]>=0) { // 如果当前字符是西文字符
			if (ch[0]!=32 && ch[0]!=9 && ch[0]!=13 && ch[0]!=10) // 如果当前字符不是空格,tab键,回车,换行,就输出
				s2=s2+ch;
		}
		else { // 如果当前字符是中文字符
			if(s.GetLength()>1) // 看看当前字符串长度是否大于1个字节
				s=s.Mid(1); 
			else {// 如果只剩1个字节,说明当前汉字是半个汉字,乱字符,不做处理
			//	dd++;
				break;
			}
			CString ch2=s.Left(1);
			if(ch2[0]<0) { // 如果接下来一个字符也是中文字符
				if (ch[0]!=-95 || ch2[0]!=-95)  // 如果不是中文空格
					s2=s2+ch+ch2;
			}
			else { // 如果不是,说明当前字符是半个汉字,乱字符
				if (ch2[0]!=32 && ch2[0]!=9 && ch2[0]!=13 && ch2[0]!=10) // 如果接下来一个字符不是空格,tab键,回车,换行,就输出
					s2=s2+ch2;
			//	dd++;
			}
		}
		
		int len=s.GetLength();
		if(len>1) {
			s=s.Mid(1);
			s.TrimLeft();
		}
	}
	return s2;
}

void RemoveSpace (CString FileName)
{// 去处文件中的中文和西文空格

	FILE * in, * out;
	in=fopen((const char *)FileName,"rt");
	if(in==NULL) {
		AfxMessageBox("Can't open the file");
		return;
	}
	FileName=ChangeFileName(FileName,"-nospace");
	out=fopen((const char *)FileName,"wt");
	if(out==NULL) {
		AfxMessageBox("Can't creat the target file");
		fclose(in);
		return;
	}

	CStdioFile inFile(in),outFile(out);
	char s[2048];
	CString line;
	while(inFile.ReadString(s,2048)) {
		line=s;
		line=RemoveSpaceOneLine(line)+'\n';
		outFile.WriteString(line);
	}
	inFile.Close();
	outFile.Close();
}

int GetSentence(CString &s)
{// 在字符串中寻找断句位置,返回句子长度值
	char w[3]; // 定义一个数组,存放一个中文字符
	int i=0;
	CString tmp=""; // 定义一个字符串,存放扫描到当前句末标点左边的部分
	
	s.TrimLeft();
	s.TrimRight();
	int n=s.GetLength();

	BOOL foundSentence = FALSE;
	BOOL PuncMatch = TRUE; // 判断引号是否匹配

	while(i<n) {
		if(s[i]>0) { // 如果发现西文字符
			if(strchr(e_puncture1,s[i])) {// 如果找到西文句末标点
				foundSentence=TRUE; 
				i++;
				break;
			}
			else // 如果不是西文句末标点
				i++;
		}
		else { // 如果是中文字符
			w[0]=s[i];
			w[1]=s[i+1];
			w[2]=0;
			if(strstr(c_puncture1,w)){ // 如果是中文句末标点
				tmp = s.Left(i); // 取出s中当前句末标点左边的部分
				if(tmp.Find("“")>=0 && tmp.Find("”")<0)
					PuncMatch = FALSE; // 如果在串中发现左引号,但没有发现右引号,则括号不匹配

				foundSentence = TRUE;
				i+=2;
				break;
				
			}
			else  // 如果不是中文句末标点
				i+=2;
		}
	}

	if(!foundSentence)
		return 0;

	while(i<n) {
		if(s[i]>0) {
			if(strchr(e_puncture1,s[i]) || strchr(e_puncture2,s[i]))
				i++;
			else
				return i;
		}
		else {
			w[0]=s[i];
			w[1]=s[i+1];
			w[2]=0;
			
			if (strcmp(w,"”")==0)
				PuncMatch = TRUE;

			if(strstr(c_puncture1,w) || strstr(c_puncture2,w))
				i+=2;
			else
			{
				if (PuncMatch) // 如果引号匹配,就认为已经找到句子切分过程,否则继续扫描
					return i;
				else
					i+=2;
			}
		}
	}
	if (PuncMatch)
		return n;
	else
		return 0;
}

void SentenceSegmentation(CString FileName)
{// 单个文件断句函数
	
	FILE *in,*out;
	CString surplus = ""; // 行尾不是以标点结尾时,会有剩余字符串

	in=fopen((const char *)FileName,"rt");
	if(in==NULL) { 
		AfxMessageBox("can't open the file"); 
		return;
	}
	FileName=ChangeFileName(FileName,"-sen");
	out=fopen((const char*)FileName,"wt");
	if(out==NULL) {
		AfxMessageBox("can't write the file");
		fclose(in);
		return;
	}
	CStdioFile inFile(in),outFile(out);
	char s[4000];
	CString line;
	int i,n;
	
	while(inFile.ReadString(s,4000)) {// 循环读入文件中每一行

		line=surplus+s; // 将当前行加上上一行剩余字符串
		surplus = ""; // 重新将surplus赋为空值

		line.TrimLeft();
		line.TrimRight();

		n=line.GetLength(); // 记录当前行的字节长度

		while((i=GetSentence(line))>0) { // 如果能从当前行中读到句子
			outFile.WriteString(line.Left(i) +'\n'); // 将该句输出到文件
			line=line.Mid(i); // 从当前行中去掉已经输出的句子
		}

		if(!line.IsEmpty()) {// 如果当前行中句子已经输出完但仍有剩余字符串
			if(n==line.GetLength() && n<60)  // 如果整行无标点且少于60字节,可能是标题文字
				outFile.WriteString(line+'\n'); // 将当前行当作一个无标点句输出
			else 
			//outFile.WriteString(line); // 否则将剩余字符写入文件,这是陈小荷书上的做法
			{//肯定不是标题,而是当前行经过断句处理剩下来的字符串
				line.TrimRight(); // 去除字符串右边的空字符
				surplus = line; // 将line作为剩余字符串加入到下一行中,等待下一个循环继续进行断句操作
			}
		}
	}
	inFile.Close();
	outFile.Close();
}

void ConvertTxt2Xml(CString FileName)
{// 将北大中文系语料库txt文件转换为带xml标记的文件

	CString CurLine,CurAuthor,CurTitle,Title,CurStyle,CurTime;

	CurLine="";
	CurAuthor="";
	CurTitle="";
	Title="";
	CurStyle="";
	CurTime="";

	int CurState=1; // 用于判断目前处理的阶段

	CString XML_Initial="<?xml version='1.0' encoding='gb2312' ?>";
//	CString XML_Initial2="<?xml-stylesheet type='text/css' href='template.css' ?>"; // 加入xml显示格式描述文件
	CString text_begin="<TEXT>";
	CString text_end="</TEXT>";
	CString text_head_begin="<TEXT_HEAD>";
	CString text_head_end="</TEXT_HEAD>";
	CString text_body_begin="<TEXT_BODY>";
	CString text_body_end="</TEXT_BODY>";

	// 打开输入文件

	FILE *fp_in;
	
	fp_in=fopen(FileName,"rt");

	if (fp_in==NULL) {
		AfxMessageBox("Can not open the file");
		return;
	}
	
	CStdioFile inFile(fp_in);
		
	while(inFile.ReadString(CurLine))
	{

		CurLine.TrimLeft(); 
		CurLine.TrimRight();
		if (CurState==1) // 处理一篇文档
		{// 一般情况下 @ 下一行紧接着就是作者,但有时候会有空行
			
			while (CurLine=="")
			{
				inFile.ReadString(CurLine);
				CurLine.TrimLeft();
				CurLine.TrimRight();
			}

			if (CurLine!="")
			{
				// 处理一般语料文件头部信息
				
				// 一般语料文件第一行是“作者”信息
				CurAuthor="<AUTHOR>"+CurLine.Mid(6)+"</AUTHOR>";
				
				// 处理人民日报语料文件头信息
/*
				Title=CurLine.Mid(6); // 取人民日报语料日期信息作为文件名
				CurTime="<TIME>"+Title+"</TIME>";
				Title="人民日报_"+Title;
*/

				// 处理北京话调查材料头部信息
/*				Title=CurLine.Mid(6);
				CurTitle="<TITLE>北京话口语调查材料——"+Title+"</TITLE>";
				inFile.ReadString(CurLine);
				CurAuthor="<AUTHOR>"+CurLine.Mid(8)+"</AUTHOR>";
*/

				// “作者”处理完后处理“篇名”
				
				inFile.ReadString(CurLine); // 如果是人民日报语料就会读进一个空行
				
				if (CurLine.Find("编辑部的故事")>=0) {// 处理编辑部的故事的标题
					Title = CurLine.Mid(19);
					CurTitle="<TITLE>编辑部的故事——"+Title+"</TITLE>";
				}
				else {// 处理一般语料文件的篇名
					Title=ChangeBracket(CurLine.Mid(6));
					CurTitle="<TITLE>"+Title+"</TITLE>";
				}
				
				// 篇名之后是类型	
				inFile.ReadString(CurLine);
				
				//要处理人民日报语料,需要注释下面这条语句
				CurStyle="<STYLE>"+CurLine.Mid(6)+"</STYLE>";
	
				// 类型之后是时代
				inFile.ReadString(CurLine);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -