項目之註釋轉換

本次項目爲註釋轉換。要求爲:將一個文件中的所有註釋(/**/、//)均轉換爲C++註釋(//)到另一個文件。

整體思路:

1.首先,提到文件那麼就需要進行打開文件讀取文件寫入文件關閉文件等這些操作,我們可以將需要進行註釋轉換的文件稱爲源文件,而將轉換後的新文件稱爲目標文件。那麼,此時就相當於將源文件通過編寫關於註釋轉換的程序生成目標文件。

既然源數據是文件類型,就需要我們在程序中讀取文件中的內容,可以通過字符的形式讀取。那麼在處理這些文件的打開讀取寫入關閉等操作中可能需要用到的函數有:

(1)打開文件的函數:fopen()

(2)按字符讀取的函數:fgetc()

(3)按字符寫入的函數:fputc()

(4)關閉文件的函數:fclose()

2.既然是註釋到註釋之間的轉換,那麼具體有哪些註釋轉換的情況呢?假設如下就是源文件的內容:

// 1.一般情況
/* int i = 0; */

// 2.換行問題
/* int i = 0; */int j = 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++註釋問題
// /*xxxxxxxxxxxx*/

我們可以將這些在註釋轉換中可能出現的情況進行梳理歸納:

既然以字符的形式讀取和寫入文件內容,就需要將讀取出來的內容進行判斷。當讀取出的內容爲'/'時應該怎麼處理,當讀取出的內容爲'*'時應該怎麼處理等等,根據分析情況,可以歸納出五種狀態,那麼下面我將通過畫圖歸納出這五種狀態分別是什麼以及它們之間狀態轉換的關係:


現在知道了這五種狀態以及它們之間的轉換,那麼在狀態進行轉換時應該進行怎樣的操作呢?下面具體說明:

1.當在普通狀態下時

(1)當源文件中取出'/'時,則將'/'寫入目標文件並且狀態變爲遇到'/'狀態。

(2)當源文件取出其他字符時,則直接將該字符寫入到目標文件並且狀態仍爲普通狀態。

2.當在遇到'/'狀態下時

(1)當源文件取出'*'時,則表示爲C註釋,需要轉換爲C++註釋,故將'/'寫入目標文件並且狀態變爲C註釋狀態。

(2)當源文件取出'/'時,則表示爲C++註釋,故直接將'/'寫入到目標文件並且狀態變爲C++註釋狀態。

(3)當源文件取出其他字符時,表示不是註釋語句,故直接寫入到目標文件並且狀態變爲普通狀態。

3. 當在C++註釋狀態時

(1)當源文件取出'\n'時,則直接將'\n'寫入目標文件並且狀態變爲普通狀態。

(2)當源文件取出其他字符時,則直接將其寫入目標文件並且狀態仍爲C++註釋狀態。

4.當在C註釋狀態時

(1)當源文件取出'*'時:

①再次讀取源文件當取出爲'*'時,則將第一次讀取到的'*'寫入目標文件並且狀態變爲遇到'*'狀態。

②再次讀取源文件當取出爲'/'時,則將第二次取出的字符還回源文件並且狀態變爲遇到'*'狀態。

③再次讀取源文件當取出爲其他字符時,則將取出的'*'以及第二次取出的字符均寫入目標文件並且狀態仍爲C註釋狀態。

(2)當源文件取出'\n'時,此時需要換行並且仍然在C註釋中,故下一行仍然爲註釋語句,故需要將'\n'和'/'和'/'寫入目標文件並且狀態仍然爲C註釋狀態。

(3)當源文件取出其他字符時,則直接將其寫入到目標文件並且狀態仍爲C註釋狀態。

5.當在遇到'*'狀態時

(1)當源文件取出'*'時,則直接將'*'寫入到目標文件並且狀態仍然爲遇到'*'狀態。

(2)當源文件取出'/'時,表示C註釋結束:

①則再次讀取源文件當取出爲'\n'時則直接將第二次讀取到的'\n'寫入到目標文件並且狀態變爲普通狀態。

②則再次讀取源文件當取出不是'\n'時則需要自己將'\n'寫入到目標文件並且將第二次讀取到的字符返還給源文件(使用ungetc()函數),狀態變爲普通狀態。

(3)當源文件取出其他字符時,則直接將其寫入到目標文件並且狀態變爲C註釋狀態。

3.根據以上思路編寫代碼如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include<Windows.h>
#include<stdio.h>
#include<stdlib.h>
//定義枚舉類型,用於表示有限的5個狀態
typedef enum State{
	NORMAL,       //普通狀態
	FOUND_SLASH,  //遇到/狀態
	CPP_COMMENT,  //c++註釋狀態
	C_COMMENT,    //c註釋狀態  
	FOUND_STAR,  //遇到*狀態
}State;
//main函數
int main()
{
	//打開源文件以及目標文件
	FILE* inputFile = fopen("C:\\Users\\Administrator\\Desktop\\input.c", "r");
	FILE* outputFile = fopen("C:\\Users\\Administrator\\Desktop\\output.c", "w");
	//判斷源文件是否爲NULL,若爲NULL則直接return 0
	if (inputFile == NULL)
	{
		goto CLOSE_FILE1;
	}
	//判斷目標文件是否爲NULL,若爲NULL則關閉源文件
	if (outputFile == NULL)
	{
		goto CLOSE_FILE2;
	}
	//CommentConvert()方法用於進行源文件到目標文件的註釋轉換的操作
	CommentConvert(inputFile, outputFile);
	//操作完畢關閉目標文件
	fclose(outputFile);
CLOSE_FILE2:
	//操作完畢關閉源文件
	fclose(inputFile);
CLOSE_FILE1:
	system("pause");
	return 0;
}
void CommentConvert(FILE* input, FILE* output)
{
	State state = NORMAL;
	int ch = 0;
	int next = 0;
	while (1)
	{
		//讀取源文件
		ch = fgetc(input);
		if (ch == EOF)
		{
			return;
		}
		//進入狀態並進行相關操作
		switch (state)
		{
		//1.當在普通狀態下時
		case NORMAL:
		    //(1)當源文件中取出'/'時,則將'/'寫入目標文件並且狀態變爲遇到'/'狀態。
			if (ch == '/') 
			{
				fputc('/', output);
				state = FOUND_SLASH;
			}
			//(2)當源文件取出其他字符時,則直接將該字符寫入到目標文件並且狀態仍爲普通狀態。
			else
			{
				fputc(ch, output);
				state = NORMAL;
			}
			break;
		//2.當在遇到'/'狀態下時
		case FOUND_SLASH:
			//(1)當源文件取出'*'時,則表示爲C註釋,需要轉換爲C++註釋,故將'/'寫入目標文件並且狀態變爲C註釋狀態。
			if (ch == '*')
			{
				fputc('/', output);
				state =C_COMMENT;
			}
			//(2)當源文件取出'/'時,則直接將'/'寫入到目標文件並且狀態變爲C++註釋狀態。
			else if (ch == '/')
			{
				fputc('/', output);
				state = CPP_COMMENT;
			}
			//(3)當源文件取出其他字符時,表示不是註釋語句,故直接寫入到目標文件並且狀態變爲普通狀態。
			else
			{
				fputc(ch, output);
				state = NORMAL;
			}
			break;
		//3. 當在C++註釋狀態時
		case CPP_COMMENT:
			//(1)當源文件取出'\n'時,則直接將'\n'寫入目標文件並且狀態變爲普通狀態。
			if (ch == '\n')
			{
				fputc('\n', output);
				state = NORMAL;
			}
			//(2)當源文件取出其他字符時,則直接將其寫入目標文件並且狀態仍爲C++註釋狀態。
			else
			{
				fputc(ch, output);
				state = CPP_COMMENT;
			}
			break;
		//4.當在C註釋狀態時
		case C_COMMENT:
			//(1)當源文件取出'*'時
			if (ch == '*')
			{
				next = fgetc(input);
				//①再次讀取源文件當取出爲'*'時,則將第二次讀取到的'*'寫入目標文件並且狀態變爲遇到'*'狀態。
				if (next == '*')
				{
					fputc('*', output);
					state = FOUND_STAR;
				}
				// ②再次讀取源文件當取出爲'/'時,將此次取出的字符返還源文件並且狀態變爲遇到'*'狀態。
				else if (next == '/')
				{
					ungetc(next, input);
					state = FOUND_STAR;
				}
				//③再次讀取源文件當取出爲其他字符時,則直接將其寫入目標文件並且狀態變爲遇到'*'狀態。
				else
				{
					fputc(ch, output);
					state = C_COMMENT;
				}
			}
			//(2)當源文件取出'\n'時,此時需要換行並且仍然在C註釋中,故下一行仍然爲註釋語句
			//故需要將'\n'和'/'和'/'寫入目標文件並且狀態仍然爲C註釋狀態。
			else if (ch == '\n')
			{
				fputc('\n', output);
				fputc('/', output);
				fputc('/', output);
			}
			//(3)當源文件取出其他字符時,則直接將其寫入到目標文件並且狀態仍爲C註釋狀態。
			else
			{
				fputc(ch, output);
				state = C_COMMENT;
			}
			break;
		//5.當在遇到'*'狀態時
		case FOUND_STAR:
			//(1)當源文件取出'*'時,則直接將'*'寫入到目標文件並且狀態仍然爲遇到'*'狀態。
			if (ch == '*')
			{
				fputc('*', output);
				state = FOUND_STAR;
			}
			//(2)當源文件取出'/'時,則表示C註釋結束,判斷下一次取出的字符是否爲'\n'
			else if (ch == '/')
			{
				next = fgetc(input);
				//①則再次讀取源文件當取出爲'\n'時則直接將第二次讀取到的'\n'寫入到目標文件並且狀態變爲普通狀態。
				if (next == '\n')
				{
					fputc(next, output);
					state = NORMAL;
				}
				//②則再次讀取源文件當取出不是'\n'時則需要自己將'\n'寫入到目標文件
				//並且將第二次讀取到的字符返還給源文件(使用ungetc()函數),狀態變爲普通狀態。
				else
				{
					fputc('\n', output);
					ungetc(next, input);
					state = NORMAL;
				}
			}
			//(3)當源文件取出其他字符時,則直接將其寫入到目標文件並且狀態變爲C註釋狀態。
			else
			{
				fputc(ch, output);
				state = C_COMMENT;
			}
			break;
		}
	}
}
以上就是關於註釋轉換的項目!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章