?? 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 + -