
我不說這個程式為什麼字元串替換還要寫這麼多代碼
總之在輸入過程中遇到的 問題我能想到的都解決了
程式的健壯性還是有的 。
我個人覺得gainchar函數是這個小程式健壯性的重要展現 末尾還有個英語單詞比對的代碼
//查昊昊
# include <stdio.h>
# include <stdlib.h>
# define N 1500 //如果想錄入x個位元組那麼就把N的數值改成x
# define MAX 14000 //當新字元串的個數已經不在 [MIN,MAX]時 此時不再複制字元串
# define MIN 2
int gainint(int *p,int a,int b);//傳回數字*p
int gainchar(char *a,int min,int max);//傳回字元串長度
int BF(char a[],char b[],int *c);//字元串比對 BF算法 a為主串,b為被檢驗的串
void shifang(int *p,char *q);//釋放int char指針
int main(){
int domain[2][3]={{MIN,0,0},{N,N,N}},length[5]={0,-1,-1,0,-1},i,j,k,n;//domain為各個字元串範圍,length[0-4]分别儲存0主字元串長度,1被替換的字元串長度,2替換的字元串長度,3比對的個數,4新字元串長度
char wen[3][23]={"請輸入一段字元串","字元串中要替換的字元串","将要替換的字元替換為"};//顯示的界面
char *p[4]={NULL,NULL,NULL,NULL};//p[i]将用于指向各字元串
char spead[2][3]={"原","新"};
int *biao,choice; //biao[]數組儲存字元比對的下标
p[0]=(char *)calloc(N+1,sizeof(char));
do{
for(i=0;i<3;i++) //有三次輸入,就是輸入wen[][]數組裡的問題的選擇
{
if(length[i]<domain[0][i]||length[i]>domain[1][i])//當字元串長度不滿足條件時重新輸入
{
printf("%s:[位元組(%d--%d)]\n",wen[i],domain[0][i],domain[1][i]);//提示輸入範圍
length[i]=gainchar(p[i],domain[0][i],domain[1][i]);
}
if(!i)//輸入原字元串ok時動态申請記憶體
{
p[1]=(char *)calloc(length[0]+1,sizeof(char));//因為字元數組的最後一位系統總是辨別'\0',是以要多申請一個記憶體
p[2]=(char *)calloc(length[0]+1,sizeof(char));
domain[1][1]=domain[1][2]=length[0];//将後來的字元串輸入範圍改變
}
if(i==1)
{
if(!length[1]) //如果使用者輸入的是'\n'則将第一位變為\n長度變為1
{
length[1]=1;
printf("你輸入的為回車符:\n");
p[1][0]='\n';
}
biao=(int *)calloc(length[0]/length[1],sizeof(int));//輸入舊的字元串完畢時申請biao記憶體,存儲比對下标
length[3]=BF(p[0],p[1],biao);//p[0]為主串,p[1]為被檢驗的串,biao[]存比對的下标,length[3]存比對的個數
if(!length[3]) //如果沒有比對的就重新輸入舊字元串
{
printf("字元串中沒有此字元串,請重新輸入");
i=0;length[1]=-1; //因為要執行i++,是以i=0
}
}
if(!length[2]) //如果length[2]即替換的字元串長度為0
{
printf("删除要替換的字元串請按0,用回車符代替請按1:\n"); // 如果想删除選中的字元串替換時直接回車有選擇
p[2][1-gainint(&length[2],0,1)]='\n';
}
if(i==2&&length[1]==length[2]&&BF(p[1],p[2],biao))//原字元串與舊字元串 相同時重新輸入p[2]
{
printf("替換的字元串與被替換的字元串相同,");
length[2]=-1;i=1;
}
}
length[4]=length[0]+(length[2]-length[1])*length[3];//計算新字元串長度
if(length[4]>=MIN&&length[4]<=MAX)
p[3]=(char *)calloc(length[4]+1,sizeof(char));//申請新字元串的記憶體
system("cls"); //清除螢幕
printf("替換的下标:\n");
for(i=0;i<length[3];i++)//每15個一行列印輸出
printf("%-3d%c",biao[i]+1,(i+1)%15?' ':'\n');
printf("\n原字元串:\n%s\n新字元串:\n",p[0]);
for(i=j=n=0;i<length[0];i++,n++)//一邊列印新字元串,一邊複制字元串到p[3]裡
if(i==biao[j]) //當i到達比對的下标
{
printf("%s",p[2]); //輸出p[2]
if(length[4]>=MIN&&length[4]<=MAX) //如果新字元串滿足長度∈[MIN,MAX] 則複制
for(k=0;k<length[2];k++)
p[3][n+k]=p[2][k]; //将p[2]存到p[3]裡
n+=length[2]-1; //增加長度
i+=length[1]-1; //增加長度
j++; //比對一個後biao[j]變為biao[j+1]
}
else
{
printf("%c",p[0][i]); //如果沒到下标就輸出原字元串的字元
if(length[4]>=MIN&&length[4]<=MAX)
p[3][n]=p[0][i]; //将不比對的複制到p[3]中
}
printf("\n原字元串長度:%-3d新字元串長度:%-3d 替換的個數:%-3d",length[0],length[4],length[3]);
do{
printf("\n0:重新輸入字元串并替換\n1:在原字元基礎上重新替換\n2:對替換後的字元串執行新一輪替換\n3:釋放指針+安全退出 輸入你的選擇(0--3):\n");
if(!gainint(&choice,0,3))
{
length[0]=0; //重新開始要讓length[0]改為0
domain[1][0]=N;
}
else if(choice==2)
{ //當使用者選擇新字元串時讓p[0]指向新字元串
p[0]=length[4]<MIN?p[0]:p[3];//當新字元串個數為2個以下時提示使用者并重新選擇
if(length[4]<MIN||length[4]>MAX)
printf("新字元串位元組已經不在[%d,%d]範圍内!\n",MIN,MAX);
else
{
shifang(NULL,p[0]); //就釋放p[0]
length[0]=length[4];//将length[0]改為新字元串的長度
domain[1][0]=length[0]>N?length[0]:N;//如果新的字元串高于250則将範圍改為新字元串的長度
}
}
}while((length[4]>MAX||length[4]<MIN)&&choice==2);//當新字元個數為<2并且使用者輸入了第二個選擇
printf("%s",choice==1||choice==2?spead[choice-1]:"\0"); //輸出"新"或"舊"
length[1]=length[2]=-1; //将其初始化
shifang(biao,p[2]); //釋放申請的記憶體
shifang(NULL,p[1]); //釋放申請的記憶體
shifang(NULL,choice<2?p[3]:NULL); //如果使用者輸入的選擇是前兩個,則p[3]就沒用了,也要釋放
}while(choice<3);
shifang(NULL,p[0]);
return 0;
}
int gainint(int *p,int a,int b)//輸入int *p直至滿足[a,b]輸入結束,傳回*p
{
do{
*p=a-1;
scanf("%d",p);
while(getchar()!='\n');
if(*p>b||*p<a)
printf("輸入有誤,請重新輸入(%d--%d):\n",a,b);
}while(*p>b||*p<a);
return *p;
}
int gainchar(char *A,int min,int max)//長度在[min,max] <閉區間> 之間時 函數結束 傳回字元串A的長度
{
int B,C;//B儲存A的長度 C記錄緩沖區的字元串
do{
B=-1; C=0; //每次使用者輸入錯誤而循環時 都要初始化
fgets(A,max+1,stdin);//從鍵盤錄入字元
while(A[++B]); //求A的字元串長度
if(A[B-1]!='\n') while(getchar()!='\n') C++; //如果緩沖區裡讀入的不是\n則記錄字元串數量
else A[--B]='\0'; //☆ 去掉\n 并且字元串長度-1
if(C||B&&B<min) //如果緩沖區有字元串或者長度不夠 則提示錯誤 但如果使用者隻輸入回車而且min!=0則不提示錯誤 但還要輸入目前字元串
printf("您輸入的字元串長度:%d位元組\n請重新輸入!\n注:隻輸入(%d--%d)個位元組!\n",B+C,min,max);
}while(C||B<min);
return B;//傳回B 即:A字元串的長度
}
int BF(char a[],char b[],int *c)//BF算法 一般o(strlen(A)+strlen(B)) 最壞o(strlen(A)*strlen(B))
{
int i=0,j=0,k=0;
do{
if (b[j]&&a[i++]==b[j]) // 繼續比較後繼字
++j;
else
{
b[j]?(i-=j):(c[k++]=i-j);
j=0; //無論b字元串是否結束因為(b[j]&&a[i++]==b[j])已經不滿足 是以j要回到初位置
}
}while(a[i-1]);
return k;
}
void shifang(int *p,char *q)
{
if(!p) free(p);
if(!q) free(q);
p=NULL; q=NULL;
}
也可以把gainchar改成這個 一樣的
int gainchar(char *A,int min,int max)//長度在[min,max] <閉區間> 之間時 函數結束 傳回字元串A的長度
{
int B,C;
do{
A[max]=B=C=0;
while((A[B++]=getchar())!='\n'&&B<max);
if(A[B-1]!='\n')
while(getchar()!='\n'&&++C);
else A[--B]=0;
if(C||B&&B<min)
printf("您錄入的字元串長度:%d位元組\n隻錄入(%d--%d)個位元組!\n",B+C,min,max);
}while(C||B<min);
return B;
}
三個經常用的字元串比對函數
int BF(char a[],char b[])//BF算法 a為主串,b為被檢驗的串`傳回b在a中的第一個下标 若無傳回0
{
int i=0,j=0;
while (a[i]&&b[j])
if (a[i++]==b[j]) ++j; // 繼續比較後繼字
else {
i-=j;
j=0;
}
return b[j]?0:i-j+1;
}
2:字元串全比對://a主串 b次串 C[0]存儲比對的個數 c[1],c[2]……存儲比對的數組下标
void BF(char a[],char b[],int *c){
int i=0,j=0,k=0;
do{
if (b[j]&&a[i++]==b[j])
++j;
else
{
b[j]?(i-=j):(c[++k]=i-j);
j=0;
}
}while(a[i-1]);
c[0]=k;
}
對上面稍微一改://傳回b在a中的個數
int BF(char a[],char b[]){
int i=0,j=0,k=0;
do{
if (b[j]&&a[i++]==b[j])
++j;
else
{
b[j]?(i-=j):k++;
j=0;
}
}while(a[i-1]);
return k;
}
還有就是 原字元串為英語句子 子字元串是一個單詞 查找出原字元串中有多少個完整的單詞 這個完整是指的 子字元串在原字元串中為一個完整的單詞 : 代碼C:
# include <stdio.h>
# define N 101
# define At(t) (t<'a'||t>'z')&&(t<'A'||t>'Z')&&t!='-'
int CMP(char a,char b){//可以通過改變這個來改變是否忽略大小寫
return a==b||b==a+32||a==b+32;
}
void BF(char a[],char b[],int c[]){//比對 a中b單詞完整的個數 c[0]存儲比對的個數 c[1],c[2]……存儲比對的單詞的 下标 使用方法和群裡的 字元串比對下标相同
int i=0,j=0,k=0;
do{
if (b[j]&&CMP(a[i++],b[j]))++j;//若a[i]與b[j]相等或是大小寫關系 繼續比較
else{
if(!b[j])
{//如果b字元串到頭了 此時需要檢查 b在a字元串是否為完整的單詞
if((i!=j)&&At(a[i-j-1])||(i==j))//i==j時 b在a字元串的串首 如果不在串首,則i!=j 此時應檢查a[i-j-1]
if(!a[i]||a[i]&&At(a[i]))//如果b在a字元串的串尾 則a[i]==0 如果不在末尾 則檢驗 a[i]
c[++k]=i-j;//存儲目前比對的單詞位置
}
else i-=j;
j=0;
}
}while(a[i-1]);
c[0]=k;
}
int main(){
char A[N]={"HOMEWORK:I am doing My-homework.your homework!Homework?oh"},B[N]={"Homework"};
int C[N],i;
BF(A,B,C);
puts(A);
puts(B);
printf("B字元串在A中個共 %d個 <忽略大小寫>\n比對的數組下标:\n",C[0]);
if(C[0])
for(i=1;i<=C[0];i++)
printf("%d ",C[i]);
printf("\n");
return 0;
}