📄 myfileapp.cpp
字号:
#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 + -