2011-01-22 96 views
57

標準C庫中是否有類似startsWith(str_a, str_b)的東西?如何檢查一個字符串是否以C中的另一個字符串開頭?

它應該指向以nullbytes結尾的兩個字符串,並告訴我第一個字符串是否也完全出現在第二個字符串的開頭。

例子:

"abc", "abcdef" -> true 
"abcdef", "abc" -> false 
"abd", "abdcef" -> true 
"abc", "abc" -> true 
+2

我認爲你的第三個例子應該有一個真實的結果。 – 2011-01-23 06:19:50

+0

@Burr:是的,沒錯。 – thejh 2011-01-23 11:24:42

回答

52

顯然有對此不存在標準的C函數。所以:

bool startsWith(const char *pre, const char *str) 
{ 
    size_t lenpre = strlen(pre), 
      lenstr = strlen(str); 
    return lenstr < lenpre ? false : strncmp(pre, str, lenpre) == 0; 
} 

請注意以上是好的,明確的,但如果你這樣做是在一個緊密的循環或非常大串的工作,它可能無法提供最佳的性能,如它掃描前面兩個字符串的全長(strlen)。諸如wj32'sChristoph's之類的解決方案可能會提供更好的性能(儘管關於矢量化的this comment超出了我對C的評價)。還請注意Fred Foo's solution,它在str上避免了strlen(他是對的,這是不必要的)。只對(非常)大的琴絃或在緊密環路中重複使用很重要,但重要時,它很重要。

+5

我應該提到*通常*的事情是將字符串作爲第一個參數,並將其作爲前綴。但我像上面一樣保留它們,因爲這似乎是你的問題是如何構建的......順序完全取決於你,但我真的應該以另一種方式完成它 - 大多數字符串函數都採用完整字符串作爲第一個參數,子字符串作爲第二個參數。 – 2011-01-22 22:31:03

+1

這是一個優雅的解決方案,但確實有一些性能問題。一個優化的實現永遠不會從每個字符串中查看超過min(strlen(pre),strlen(str))字符,也不會超越第一個不匹配。如果琴絃很長,但早期的不匹配很常見,它會非常輕便。但是由於這個實現將兩個字符串的全部長度都放在前面,所以即使字符串在第一個字符中不同,它也會強制最差情況下的性能。這是否真的取決於具體情況,但這是一個潛在的問題。 – 2018-01-06 11:33:02

+0

@TomKarzes:當然,我被字符串長度是一個已知值的語言/環境所迷惑,而不是我們必須弄清楚的。 :-) [wj32的解決方案](https://stackoverflow.com/a/4771055/157247)提供更好的性能。只對(非常)大字符串或緊密循環很重要,但重要時,它很重要。 – 2018-01-06 11:38:00

101

有這個沒有標準的功能,但你可以定義

bool prefix(const char *pre, const char *str) 
{ 
    return strncmp(pre, str, strlen(pre)) == 0; 
} 

我們不必擔心str因爲根據C標準是小於pre (7.21.4.4/2):

strncmp函數不超過n字符(即跟隨一個空字符的字符不進行比較)從陣列比較指向s1到陣列由s2指向。」

+4

爲什麼答案不是?顯然,答案是肯定的,它被稱爲`strncmp`。 – Jasper 2017-02-13 00:39:39

5

我在寫優雅的代碼專家,但...

int prefix(const char *pre, const char *str) 
{ 
    char cp; 
    char cs; 

    if (!*pre) 
     return 1; 

    while ((cp = *pre++) && (cs = *str++)) 
    { 
     if (cp != cs) 
      return 0; 
    } 

    if (!cs) 
     return 0; 

    return 1; 
} 
4

使用strstr()功能。 Stra == strstr(stra, strb)

+1

這似乎有點倒退 - 如果strb是一個前綴,那麼即使它應該從非常短的初始段中清楚,您仍然會穿過整個stra。 – StasM 2011-01-22 23:02:04

22

我可能會用strncmp()去,但只是爲了好玩原始的實現:

_Bool starts_with(const char *restrict string, const char *restrict prefix) 
{ 
    while(*prefix) 
    { 
     if(*prefix++ != *string++) 
      return 0; 
    } 

    return 1; 
} 
1

因爲我跑了接受的版本並且有一個很長的STR一個問題,我不得不在增加以下邏輯:

bool longEnough(const char *str, int min_length) { 
    int length = 0; 
    while (str[length] && length < min_length) 
     length++; 
    if (length == min_length) 
     return true; 
    return false; 
} 

bool startsWith(const char *pre, const char *str) { 
    size_t lenpre = strlen(pre); 
    return longEnough(str, lenpre) ? strncmp(str, pre, lenpre) == 0 : false; 
} 
1

優化(第2節 - 校正。):

uint32 startsWith(const void* prefix_, const void* str_) { 
    uint8 _cp, _cs; 
    const uint8* _pr = (uint8*) prefix_; 
    const uint8* _str = (uint8*) str_; 
    while ((_cs = *_str++) & (_cp = *_pr++)) { 
     if (_cp != _cs) return 0; 
    } 
    return !_cp; 
} 
-5

優化:

boolean StartsWith(char *s1, char *s2) 
{ 
    while (*s1++ == *s2++) 
    { 
    } 

    return *s2 == 0; 
} 
相關問題