2010-09-22 21 views
0

我剛剛開始接觸C編程,並會讚賞我的ReplaceString函數的批評。 它看起來非常快(它不會爲結果字符串分配除malloc以外的任何內存),但它看起來非常冗長,我知道它可以做得更好。改進C ReplaceString函數的建議?

用法示例:

printf("New string: %s\n", ReplaceString("great", "ok", "have a g grea great day and have a great day great")); 
printf("New string: %s\n", ReplaceString("great", "fantastic", "have a g grea great day and have a great day great")); 

代碼:

#ifndef uint 
    #define uint unsigned int 
#endif 

char *ReplaceString(char *needle, char *replace, char *haystack) 
{ 
    char *newString; 
    uint lNeedle = strlen(needle); 
    uint lReplace = strlen(replace); 
    uint lHaystack = strlen(haystack); 
    uint i; 
    uint j = 0; 
    uint k = 0; 
    uint lNew; 
    char active = 0; 
    uint start = 0; 
    uint end = 0; 

    /* Calculate new string size */  
    lNew = lHaystack; 

    for (i = 0; i < lHaystack; i++) 
    { 

     if ((!active) && (haystack[i] == needle[0])) 
     { 
      /* Start of needle found */ 
      active = 1; 
      start = i; 
      end = i; 
     } 
     else if ((active) && (i-start == lNeedle)) 
     { 
      /* End of needle */ 
      active = 0; 
      lNew += lReplace - lNeedle; 
     } 
     else if ((active) && (i-start < lNeedle) && (haystack[i] == needle[i-start])) 
     { 
      /* Next part of needle found */ 
      end++; 
     } 
     else if (active) 
     { 
      /* Didn't match the entire needle... */ 
      active = 0; 
     } 

    } 
    active= 0; 
    end = 0; 


    /* Prepare new string */ 
    newString = malloc(sizeof(char) * lNew + 1); 
    newString[sizeof(char) * lNew] = 0; 

    /* Build new string */ 
    for (i = 0; i < lHaystack; i++) 
    { 

     if ((!active) && (haystack[i] == needle[0])) 
     { 
      /* Start of needle found */ 
      active = 1; 
      start = i; 
      end = i; 
     } 
     else if ((active) && (i-start == lNeedle)) 
     { 
      /* End of needle - apply replacement */ 
      active = 0; 

      for (k = 0; k < lReplace; k++) 
      { 
       newString[j] = replace[k]; 
       j++; 
      } 
      newString[j] = haystack[i]; 
      j++; 

     } 
     else if ((active) && (i-start < lNeedle) && (haystack[i] == needle[i-start]) 
       ) 
     { 
      /* Next part of needle found */ 
      end++; 
     } 
     else if (active) 
     { 
      /* Didn't match the entire needle, so apply skipped chars */ 
      active = 0; 

      for (k = start; k < end+2; k++) 
      { 
       newString[j] = haystack[k]; 
       j++; 
      } 

     } 
     else if (!active) 
     { 
      /* No needle matched */ 
      newString[j] = haystack[i]; 
      j++; 
     } 

    } 

    /* If still matching a needle... */ 
    if (active && (i-start == lNeedle)) 
    { 
     /* If full needle */ 
     for (k = 0; k < lReplace; k++) 
     { 
      newString[j] = replace[k]; 
      j++; 
     } 
     newString[j] = haystack[i]; 
     j++; 
    } 
    else if (active) 
    { 
     for (k = start; k < end+2; k++) 
     { 
      newString[j] = haystack[k]; 
      j++; 
     } 
    } 

    return newString; 
} 

任何想法?非常感謝!

+3

你不允許使用字符串中的函數。 h'? – 2010-09-22 17:28:03

+0

@Carl,特別是?(不要告訴我有一個ReplaceString在那裏!!)) – HoboBen 2010-09-22 17:33:32

+2

我不認爲有,但有'strstr()'找到一個子字符串。 – linuxuser27 2010-09-22 17:38:04

回答

3

不要調用strlen(haystack)。您已經檢查字符串中的每個字符,所以計算字符串長度是隱含於你的循環,如下所示:

for (i = 0; haystack[i] != '\0'; i++) 
{ 
    ... 
} 
lHaystack = i; 
+0

整潔,感謝Brian! – HoboBen 2010-09-22 18:02:49

1

第一次循環時,應該在需要更換的位置保留索引,並跳過功能的strcopy/Replace部分。這會導致一個循環,你只能從乾草堆或替換爲新字符串執行strncpy。

2

你可能正在以自己的方式來練習。如果是這樣,你會得到許多努力點。

如果沒有,您可以通過使用C運行時庫(CRT)中的函數與編寫自己的等效函數來節省時間。例如,您可以使用strstr來查找要替換的字符串。其他字符串操作函數也可能對您有用。

一個很好的練習就是完成這個例子讓你滿意,然後用CRT重新編碼,看看代碼和執行速度有多快。

+0

謝謝;我一定會這樣做。我可以想到實現這個功能的幾種方法,並且編寫和計時它們聽起來都是一個好主意。 – HoboBen 2010-09-22 17:54:31

+1

對於新的編碼器,這個代碼很好看。你也可以考慮使用指針算術來代替索引,例如。 '(char * next = haystack,i = 0; i 2010-09-22 18:02:25

0

使參數const

char *ReplaceString(const char *needle, const char *replace, const char *haystack) 

哦...是函數應該每字只能工作一次?

ReplaceString("BAR", "bar", "BARBARA WENT TO THE BAR")

0

我的一個建議,無關與提高性能,但提高了可讀性。

「可愛」的參數名稱比描述性的要難得多。你認爲以下哪些參數能更好地表達其目的?

char *ReplaceString(char *needle, char *replace, char *haystack) 
char *ReplaceString(char *oldText, char *newText, char *inString) 

有了之一,你必須有意識地將一個名稱映射到一個目的。另一方面,目的是名稱。在試圖理解一段代碼的同時,在你的腦海中混雜着一堆名字映射會變得困難,尤其是隨着變量數量的增加。

當你是唯一一個使用你的代碼時,這看起來並不重要,但當你的代碼被其他人使用或閱讀時,這是非常重要的。有時候,「別人」就是你自己,一年後,看着你自己的代碼,想知道爲什麼你要通過乾草堆尋找並試圖替換針頭)

+1

在這種情況下,我會說每個C程序員都應該使用_needle_和_haystack_,因爲這些是strstr()參數的傳統名稱。 – ninjalj 2010-09-22 18:16:06

+0

是的,我習慣了PHP和一些BASIC&Pascal方言,儘管我很欣賞這個問題 – HoboBen 2010-09-22 18:25:52