#include <stdio.h>
#include <string.h>
void count(FILE *fp_1);//实现记录每一个大写/小写字母;并输出到终端中
void replace(FILE *fp_1, FILE *fp_2);//实现更换
int search(char *loadZone, char *objectString, int loadZoneIndex, int objectStringIndex);//实现找到每一行中第一个目标字符串出现的位置并返回该位置的下标
void write(FILE *fp_2, char *loadZone, char *objectString, char *replaceString, int loadZoneIndex, int objectStringIndex, int replaceStringIndex);//实现对缓冲行的循环判断和写入
int main()
{
FILE *fp_1 = fopen("C:\\VS Code\\C Programs\\CFilesLearning\\files\\FilesDemo2_2_1.txt", "r");
if (fp_1 == NULL)
{
perror("File open failed:");
exit(0);
}
FILE *fp_2 = fopen("C:\\VS Code\\C Programs\\CFilesLearning\\files\\FilesDemo2_2_2.txt", "w");
if (fp_2 == NULL)
{
perror("File open failed:");
exit(0);
}
count(fp_1);
fseek(fp_1, 0, 0);//注意count函数使用fp_1文件指针对文件1进行遍历,遍历结束指针会移到文件尾,下一步replace函数再次遍历文件1,则需要用fseek函数把指针移到文件1开头
replace(fp_1, fp_2);
fclose(fp_1);
fclose(fp_2);
return 0;
}
void count(FILE *fp_1)
{
char load = '\0';
int characterTable[26] = {0};//使用一个int类型数组记录每一个字母出现的次数
while (fscanf(fp_1, "%c", &load) != EOF)
{
if (load >= 'a' && load <= 'z')
{
characterTable[load - 'a']++;
}
else if (load >= 'A' && load <= 'Z')
{
characterTable[load - 'A']++;
}
}
for (int i = 0; i < 26; i++)//遍历输出此数组
{
printf("%c/%c:%d\n", i + 'A', i + 'a', characterTable[i]);
}
}
void replace(FILE *fp_1, FILE *fp_2)
{
printf("Please enter the object string:\n");
char objectString[1000] = {'\0'};
char load = '\0';
int objectStringIndex = 0;
while (1)//读取目标字符串
{
load = getchar();
if (load == '\n')
{
break;
}
else
{
objectString[objectStringIndex++] = load;
}
}
printf("Your object string is:\n");
for (int i = 0; i < objectStringIndex; i++)
{
printf("%c", objectString[i]);
}
printf("\n");
printf("Please enter the replace string:\n");
char replaceString[1000] = {'\0'};
int replaceStringIndex = 0;
while (1)//读取要替换成的字符串
{
load = getchar();
if (load == '\n')
{
break;
}
else
{
replaceString[replaceStringIndex++] = load;
}
}
printf("Your replace string is:\n");
for (int i = 0; i < replaceStringIndex; i++)
{
printf("%c", replaceString[i]);
}
char loadZone[1000] = {'\0'};
int loadZoneIndex = 0;
while (1) // 把整个文本文件按行拆分成一个个字符串
{
if (fscanf(fp_1, "%c", &load) == EOF)//如果scanf返回终止符EOF,则对最后一行进行如下操作
{
// 这里对最后一行判断并写完再退出,同理,见下面非最后一行的操作
if (strstr(loadZone, objectString) != NULL)
{
write(fp_2, loadZone, objectString, replaceString, loadZoneIndex, objectStringIndex, replaceStringIndex);
}
else
{
for (int i = 0; i < loadZoneIndex; i++)
{
fprintf(fp_2, "%c", loadZone[i]);
}
fprintf(fp_2, "%c", '\n');
}
for (int i = 0; i < loadZoneIndex; i++)
{
loadZone[i] = '\0';
}
loadZoneIndex = 0;
break;
}
//如果未读到最后一行,则以'\n'为标志,将每一行存入缓冲区(缓冲字符串loadZone中)
if (load != '\n')
{
loadZone[loadZoneIndex++] = load;
}
else if (load == '\n')//读到'\n',判断一行读完,开始进行判断和写入操作
{
if (strstr(loadZone, objectString) != NULL)//调用函数strstr,判断缓冲区是否有目标字符串
{
//若有,则调用write函数
write(fp_2, loadZone, objectString, replaceString, loadZoneIndex, objectStringIndex, replaceStringIndex);
}
else//若没有,则把缓冲区的字符全部写入
{
for (int i = 0; i < loadZoneIndex; i++)
{
fprintf(fp_2, "%c", loadZone[i]);
}
fprintf(fp_2, "%c", '\n');//一行输出完毕,加上换行符
}
for (int i = 0; i < loadZoneIndex; i++)//清空缓存区,准备存入下一行
{
loadZone[i] = '\0';
}
loadZoneIndex = 0;
}
}
}
int search(char *loadZone, char *objectString, int loadZoneIndex, int objectStringIndex)
{
//实现返回缓冲区中第一次出现目标字符串的第一个字符的下标
int objectStringPosition = 0;
int flag = 0;
int k = 1;
for (int i = 0; i < loadZoneIndex; i++)
{
if (loadZone[i] == objectString[0] && flag != 1)
{
objectStringPosition = i;
flag = 1;
continue;
}
if (flag == 1)
{
if (loadZone[i] == objectString[k++])
{
if (k == objectStringIndex)
{
break;
}
else
{
continue;
}
}
else
{
flag = 0;
k = 1;
}
}
}
return objectStringPosition;
}
void write(FILE *fp_2, char *loadZone, char *objectString, char *replaceString, int loadZoneIndex, int objectStringIndex, int replaceStringIndex)
{
int objectStringPosition = 0;//目标字符串的第一个字符在缓冲区中第一次出现的下标
int currentNeedle = 0;//记录当前在缓冲区中的下标
objectStringPosition = search(loadZone, objectString, loadZoneIndex, objectStringIndex);
while (1)//循环判断,可能一行出现多个目标字符串
{
for (int i = currentNeedle; i < objectStringPosition; i++)//在目标串前的缓冲区字符写入文件2
{
fprintf(fp_2, "%c", loadZone[i]);
}
for (int i = 0; i < replaceStringIndex; i++)//当前下标读到目标字符串第一个字符出现的位置,开始写入要替换的字符串
{
fprintf(fp_2, "%c", replaceString[i]);
}
currentNeedle = objectStringPosition + objectStringIndex;//更新当前下标,跳到第一个目标字符串最后一个字符的后一位
//遍历,用缓冲区后面字符串把第一个目标字符串及其前面的字符全部覆盖,这样后面若还有目标字符串,则因为第一个被覆盖,其又变成第一个
for (int i = 0; i < loadZoneIndex - currentNeedle; i++)
{
loadZone[i] = loadZone[i + currentNeedle];
}
for (int i = loadZoneIndex - currentNeedle; i < loadZoneIndex; i++)//多余的字符消掉
{
loadZone[i] = '\0';
}
loadZoneIndex -= currentNeedle;//缓冲区数组长度更新
currentNeedle = 0;
if (strstr(loadZone, objectString) == NULL)//继续寻找,若没有目标字符串了,则输出剩下的
{
// 输出剩下的
for (int i = currentNeedle; i < loadZoneIndex; i++)
{
fprintf(fp_2, "%c", loadZone[i]);
}
fprintf(fp_2, "%c", '\n');
break;
}
else // 若还有目标字符串,则更新位置,重复上述过程
{
objectStringPosition = search(loadZone, objectString, loadZoneIndex, objectStringIndex);
}
}
//最终跳出循环,完成对文件中一行字符的处理
}
初学编程,逻辑和实现很是拙劣和冗杂,若有不当之处,敬请多多指出和交流。