将c语言的注释风格 转换 为 C++的风格需要遇到如下问题 :
//1.一般情况
int num = 0;
/int i = 0; /// 2.换行问题/ * int i = 0; * / int i = 0; / * int i = 0; * /int j = 0; // 3.匹配问题/ * int i = 0; / * xxxxx * /// 4.多行注释问题/ int i = 0; int j = 0; int k = 0; / int k = 0; // 5.连续注释问题/ * // * /// 6.连续的* /问题/ * ///7.C++注释问题// / * xxxxxxxxxxxxxxx * /说明不是简单的将/ * * /变成//就可可以了,从上面我们可以在遍历input.c可以发现4中状态遇到C语言状态,c ++状态,无状态(没有注释的状态),结束状态(遍历完成的状态)。可以把问题看成四种状态的来回。
## CommentConvert.h
#include
#include
#include
void DoCommentConvert(FILE *fpIn, FILE *fpOut);//注释处理函数
void DoNUL_STATE(FILE *fpIn, FILE *fpOut, enum State *state);//处理无状态的函数
void DoC_STATE(FILE *fpIn, FILE *fpOut, enum State *state);//处理C语言状态的函数
void DoCPP_STATE(FILE *fpIn, FILE *fpOut, enum State *state);//处理C++状态的函数
enum State
{
NUL_STATE,
C_STATE,
CPP_STATE,
END_STATE,
};
void DoCommentConvert(FILE *fpIn, FILE *fpOut)
{
enum State state = NUL_STATE;//初始化为无状态
while (state != END_STATE)//当结束状态的时候跳出
{
switch (state)//选择状态
{
case NUL_STATE:DoNUL_STATE(fpIn, fpOut, &state);
break;
case C_STATE:DoC_STATE(fpIn, fpOut, &state);
break;
case CPP_STATE:DoCPP_STATE(fpIn, fpOut, &state);
break;
}
}
}
DoCommentConvert()设定了初始化的的无状态。通过一个while循环将状态来回转换。
void DoNUL_STATE(FILE *fpIn, FILE *fpOut, enum State *state)
{
int first = fgetc(fpIn);
switch(first)
{
case'/':
{
int second = fgetc(fpIn);;
switch(second)
{
case'*':
{
fputc('/',fpOut);
的fputc( '/',fpOut);
* state = C_STATE;
打破;
}
case'/':
{
fputc(first,fpOut);
的fputc(第二,fpOut); * state = CPP_STATE; 打破; } default: { putc(first,fpOut); putc将(第二,fpOut); 打破; } } 打破;
}
情况下EOF:
*状态= END_STATE;
打破;
默认值:
的fputc(第一,fpOut); 打破;
}
}
进入无状态函数。将文件指针所指向的字符通过龟etc(fpin)赋值给一个整形第一。通过开关语句判断这个第一是不是* / 。如果不是,那么看看是不是文件的数据流结束了EOF,如果再不是那么这个肯定是一个字符,只需要将它输入到output.c文件里。接下来如果是 / ,还需要判断接下来的一个字符second是号,还是 / *。如果是,那么可已确定是/ 组合,是C语言风格。需要将两个/写入到output.c中。将状态改为C_STATE即C语言状态如果是/ ,那么可以确定是//组合,是C ++风格。只需要将第一和第二直接写入到输出中。将状态改为CPP_STATE即C ++状态 void DoC_STATE(FILE fpIn,FILE * fpOut,enum State * state)
{
int first = fgetc(fpIn);
switch(first)
{
case'*':
{
int second = fgetc(fpIn);
switch(second)
{
case'/':
{
* state = NUL_STATE;
int third = fgetc(fpIn);
if(third!='\ n')
{
ungetc(third,fpIn);
fputc('\ n',fpOut);
}
else
{
ungetc(third,fpIn);
}
打破;
}
case'*':
{
ungetc(second,fpIn);
fputc(第二,fpOut);
打破;
}
default:
fputc(first, fpOut);
fputc(second, fpOut);
break;
}
break;
}
case '\n':
{
fputc(first, fpOut);
fputc('/', fpOut);
fputc('/', fpOut);
break;
}
default:
fputc(first, fpOut);
break;
}
}
转到C语言后继续获取字符,由于C语言注释还有一个结束标志 */。接下来的字符还需要一一判断。
如果fisrt 是一个 * 号时,需要进一步判断second是一个什么字符。
如果 second 是一个 / 还需要进行第三次判断。
如果 third 是一个 \n 说明 需要换行了。写入一个/n字符。
如果 third 是一个 其他字符,那么就不用管,这时C语言注释已经结束了。需要将注释状态改为无状态 State = NUL_STATE
如过第二放是继续写入, 不是C语言的结束标志。如果首先是一个换行符就将换行符写入到output.c后,再加入两个//。如果first是一个非注释符的字符,就直接写入到这个output.c里去 .void DoCPP_STATE(FILE fpIn,FILE * fpOut,enum State * state) { int ch = fgetc(fpIn); switch(ch) { case’\ n’: { fputc(ch,fpOut); * state = NUL_STATE; 打破; } 情况下EOF: { *状态= END_STATE; 打破; } default: { fputc(ch,fpOut); 打破; } } }
这个函数是用来处理C++状态,由于是C++状态相当于不改变什么东西。需要关心的是换行问题和结束问题。 其他的东西照写不误。
如果是 \n ,那么需要注意的是换行后还是C++状态吗?,显然不是了换行后可能遇到C语言状态,也可能是无状态 。但是 无状态能够进一步判断是否进入了 C语言状态。
系统( “暂停”);
出口(EXIT_FAILURE);
}
FILE * fpOut = fopen((const char *)DocumentNameCopy,“wb”);
if(fpOut == NULL)
{
fclose(fpIn);
perror(“fpOut打开文件失败!\ n”);
系统( “暂停”);
出口(EXIT_FAILURE);
}
DoCommentConvert(fpIn,fpOut);
//转换完成文件关闭
FCLOSE(fpIn);
FCLOSE(fpOut);
}
空隙MakeNewDocument(字符* DocumentNameOld,字符* DocumentNewName)//创建一个同名的复制版文件夹
{
INT大小= 0;
strcpy(DocumentNewName,DocumentNameOld);
size = strlen(DocumentNewName);
DocumentNewName[size - 5] = '\0';
strcat(DocumentNewName, "复制版");
_mkdir(DocumentNewName);//创建文件夹
}
void listFiles(const char *dir,char *DocumentNameCopy)
{
char DocumentNew[200];//创建一个新的文件夹名字
char DocumentName1[200];//用于文件名字的复制
char DocumentName2[200];//用于文件遍历的名字
char FinshMessage[100] = "done!_";
intptr_t handle;
struct _finddata_t findData;
strcpy(DocumentNew, dir);//当前文件夹的名字拷贝给新文件夹
strcat(DocumentNew, "\\\\*.*");//给新文件夹的名字后面加上通配符后缀
strcat(DocumentNameCopy, "\\\\*.*");//给新文件夹的名字增添上通配符
handle = _findfirst(DocumentNew, &findData);//比对文件夹的名字和数据,将其返回一个句柄
MakeNewDocument(DocumentNameCopy, DocumentName1);//将拷贝的名字 添加上“复制版”得到 DocumentName1
strcpy(DocumentName2, DocumentName1);//将获得的名字防在DocumentName2里 用于接下来的遍历
if (handle == -1)//如果句柄返回失败就终止程序
{
printf("Failed to find first file!\n");
system("pause");
return;
}
do
{
char tmp_name[200];
strcpy(tmp_name, findData.name);
if (findData.attrib & _A_SUBDIR)
{
if (strcmp(findData.name, ".") == 0 || strcmp(findData.name, "..") == 0)
//遍历文件夹里的文件 如果是子文件夹 就跳过
{
continue;
}
strcat(DocumentName2, "\\\\");
strcat(DocumentName2, findData.name);
strcpy(DocumentNew, dir);
strcat(DocumentNew, "\\\\");
//调整文件夹的名字,使其能够对应fpin的读取个格式
strcat(DocumentNew, findData.name);
listFiles(DocumentNew,DocumentName2);
//遇到文件夹的时候进行递归操作
strcpy(DocumentNew, dir);
strcat(DocumentNew, "\\\\*.*");
//当上一个函数完成后,也就是说文件夹遍历完毕,添加好通配符,为下一个文件夹做准备
}
else
{
_Work(DocumentNew, tmp_name, DocumentName1);
//当读取到的不是文件夹后,对其惊喜注释转换操作
}
} while (_findnext(handle, &findData) == 0);
//一个文件夹 遍历完成
strcat(FinshMessage, dir);
strcat(FinshMessage,“\ n”);
的printf(FinshMessage);
_findclose(手柄);
返回;
}
这个黑科技写的很烂,主要是对这个递归不熟悉。但是神奇的是这个程序能跑。能够遍历以下文件夹里的所有文件,包括了文件的嵌套。另外附赠一个链接,我就是看这个博客才学会遍历文件夹。
https://img-blog.csdn.net/20180825145503853?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0hfU3Ryb25n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70 )![ 这里写图片描述] (https://img-blog.csdn.net/20180825145512828?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0hfU3Ryb25n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70 )