2011-11-29 137 views
0

我期待創建一個C函數,它將根據用戶輸入的條目搜索文件並能夠替換那裏的文件。我見過類似的C++示例,但我不太瞭解C++。任何建議或示例代碼,以幫助我開始將是驚人的。我的理解是,我需要打開原始文件進行閱讀,打開一個新的文件進行寫入,每次讀取一行文件的原始文件,將該行寫入新文件,完成後刪除原始文件,然後重命名新文件文件與原始文件的名稱。查找和替換功能

與說明任何建議或示例代碼將是最有幫助的

編輯經過進一步的研究,我在想,如果我能想出辦法來FREAD文件,搜索文件,進行了更改,並將其寫回到文件中會更容易。

+1

替換是困難的,除非你用一個完全相同大小的字符串替換原件。否則,下一個最好的事情就是記憶地圖並使用'memmove'。 –

+0

如果我有條目存儲在一個數組中,我可以檢查替換的條目在替換之前是否會超出數組的大小。對? – Questioneer

+1

較大的*和*較小都有問題,因爲您需要移動所有後續文件內容。唯一容易的是平面覆蓋。 –

回答

1

閱讀,並與線導向功能寫作很容易,獲取用戶輸入scanf函數經常被使用。

困難的部分是做了足夠的錯誤檢查,其中大部分遺漏,直到爲時已晚。

這是一個很好的但並不完美的例子,使用最佳實踐。總是有更好和更有效的方式,但與此開始做這項工作,讓您和C.好

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <errno.h> 

#define BUFFER_SIZE 512 

static void searchAndReplace(char* original_file,char* destination_file,char *searchString,char *replacementString){ 
    FILE* original = NULL; 
    FILE* modified = NULL; 
    char origLine[BUFFER_SIZE]; //buffer, assuming the longest line will be BUFFER_SIZE -1 characters, being the null terminator the last one 
    size_t searchStringLength = strlen(searchString);//length without terminating NULL. 
    memset(origLine,0,BUFFER_SIZE);// filling with nulls just in case 
    original = fopen(original_file,"r"); 
    if(!original){ 
     printf("Error opening file for reading : %s \n",original_file); 
     perror("Cause of Error"); 
     exit(2); 
    } 
    modified = fopen(destination_file,"w+"); 
    if(!modified){ 
     printf("Error opening file for writing: %s \n",destination_file); 
     perror("Cause of Error"); 
     exit(2); 
    } 

    while(NULL != (fgets(origLine,BUFFER_SIZE,original))){ 
     char* searchStringPos=NULL; 
     /*it begins to concatenate at the beginning of the string, next position is strlen(searchString) from the last 
      searchString pointer position*/ 
     char* lastConcatPos = origLine; 
     if(feof(original) != 0){ 
      break; 
     } 
     while ((searchStringPos = strstr(lastConcatPos,searchString)) != NULL){ 
      /* offset between position where searchStringPos was found and the last position being concantenated */ 
      char tempBuffer[BUFFER_SIZE]; 
      size_t sizeToConcatenate = (size_t)(searchStringPos - lastConcatPos); 
      /* if searchString was located at the beginning of the line or right after the last occurrence do nothing */ 
      if(sizeToConcatenate >0){ 
       strncpy(tempBuffer,lastConcatPos,sizeToConcatenate); 
       tempBuffer[sizeToConcatenate]='\0'; 
       fputs(tempBuffer,modified); 
      } 
      fputs(replacementString, modified); 
      lastConcatPos = searchStringPos + searchStringLength;/* continue search after current occurrence*/ 
     } 
     fputs(lastConcatPos,modified); 
    } 
    fclose(original); 
    fclose(modified); 
} 

static void askUserForInput(char* data_storage,char* text_message){ 
    int result = 0; 
    do{ 
     //printf("%s, | %s\n | result = %i",text_message,data_storage,result); 
     printf("%s\n",text_message); 
     fflush(stdout); 
     result = scanf("%s",data_storage); 
    }while(result ==0); 
} 

int main(int argc,char* argv[]){ 
    /* Use: program <original_filename> <modified_filename> <string_to_search> <replacement_string> or 
    * program for asking the user for input */ 

    if(argc == 5){ 
     searchAndReplace(argv[1],argv[2],argv[3],argv[4]); 
    }else if(argc == 1){ 
     char origin_file[128]; 
     char destination_file[128]; 
     char search_string[128]; 
     char replacement_string[128]; 
     askUserForInput(origin_file,"Enter origin file please"); 
     askUserForInput(destination_file,"Enter destination file please"); 
     askUserForInput(search_string,"Enter search string please"); 
     askUserForInput(replacement_string,"Enter replacement string please"); 
     searchAndReplace(origin_file,destination_file,search_string,replacement_string); 
    }else{ 
     printf("Usage:\n %s <original_filename> <modified_filename> <string_to_search> <replacement_string>\n or" 
       "%s without parameter for asking for input",argv[0],argv[0]); 
     exit(1); 
    } 
    return 0; 
} 

編輯的見解:還有很大的提升空間,比如檢查每個空指針功能,改變searchAndReplace根據錯誤的類型返回int = 0成功和別人並讓呼叫者管理程序行爲的其他部分一樣再次嘗試,而不是退出程序等

而且printf上錯誤處理部分應替換爲fprintf(stderr,"message",..)這是您可以用來改進和學習的一些想法和概念 多很多。希望你有很多樂趣

1

嘗試這樣: -

#include <stdio.h> 
#include <string.h> 

#define MAX_LEN_SINGLE_LINE  120 // ? 

int main() 
{ 
    const char fileOrig[32] = "myOriginalFile.txt"; 
    const char fileRepl[32] = "myReplacedFile.txt"; 
    const char text2find[80] = "lookforme"; 
    const char text2repl[80] = "REPLACE_WITH_THIS"; 

    char buffer[MAX_LEN_SINGLE_LINE+2]; 
    char *buff_ptr, *find_ptr; 
    FILE *fp1, *fp2; 
    size_t find_len = strlen(text2find); 

    fp1 = fopen(fileOrig,"r"); 
    fp2 = fopen(fileRepl,"w"); 

    while(fgets(buffer,MAX_LEN_SINGLE_LINE+2,fp1)) 
    { 
     buff_ptr = buffer; 
     while ((find_ptr = strstr(buff_ptr,text2find))) 
     { 
      while(buff_ptr < find_ptr) 
       fputc((int)*buff_ptr++,fp2); 

      fputs(text2repl,fp2); 

      buff_ptr += find_len; 
     } 
     fputs(buff_ptr,fp2); 
    } 

    fclose(fp2); 
    fclose(fp1); 

    return 0; 
} 
+0

以上不要求用戶輸入,我已經看到這個代碼。請看我最初的問題,我的編輯請。 – Questioneer

+0

@Questioneer:[編程意味着有時你必須將兩個塊對齊](https://blogs.msdn.com/themes/blogs/generic/post.aspx?WeblogApp=oldnewthing&y=2009&m=08&d=04&WeblogPostID=9856634&GroupKeys= )。你永遠不會總是得到你需要的代碼,你可能也得自己去做一些工作。 –

0

一個很好的解決方法,創建一個lex掃描器與愚蠢的語法,只識別文字。在下面的例子中,「aaaa」被「AAAA」等替代。輸出不被重新掃描。

%% 

"aaaa" { fputs("AAAA", stdout); } 

"bbbb" { fputs("BBBB", stdout); } 

"cccc" { fputs("CCCC", stdout); } 

. { ECHO; } 

[ \t\r\n]+ { ECHO; } 

%% 

這一個Makefile片段:

#Makefile 

LDFLAGS := -lfl 
################### 

replace: replace.o 
    $(CC) -o [email protected] $? $(LDFLAGS) 

replace.o: replace.c 

replace.c: replace.l 

(但它可能會更容易,只需使用SED) 這種方法的一個很好的特性是,(F)法做了所有的緩衝,只需要最少量的緩衝。由於lex創建了DFA,因此該方法也很快:實際上,所有字符串都是並行匹配