2011-01-22 19 views
57

標準CライブラリにstartsWith(str_a, str_b)のようなものはありますか?文字列がCで別の文字列で始まるかどうかをチェックする方法は?

nullbytesで終わる2つの文字列へのポインタをとり、最初の文字列も2番目の文字列の先頭に完全に現れるかどうかを教えてください。

例:

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

私はあなたの3番目の例が真の結果を持つべきだと思います。 –

+0

@Burr:はい、そうです。 – thejh

答えて

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は私のケンカンを超えています)。 Fred Foo's solutionもあり、が strにあるのを避けている(彼は正しい、それは不要である)。タイトなループで(非常に)大きな弦や繰り返し使用する場合にのみ重要ですが、重要な場合は重要です。

+5

私は、文字列が最初のパラメータになり、接頭辞が2番目になるように*通常のことが言及する必要があります。しかし、あなたの質問がどのように枠組みされているかのように思えたので、私は上記のようにしていました...注文はあなた次第ですが、私は本当にそれを他の方法で行うべきでした - ほとんどの文字列関数は第1引数、第2引数としての部分文字列。 –

+1

これは洗練されたソリューションですが、パフォーマンスに問題があります。最適化された実装では、各文字列のmin(strlen(pre)、strlen(str))文字以上を見たり、最初の不一致を超えて見ることはありません。文字列が長いが初期のミスマッチが一般的だった場合は、非常に軽量になります。しかし、この実装は両方の文字列の完全な長さを前面に持っているので、文字列が最初の文字で異なる場合であっても、最悪の場合のパフォーマンスを強制します。この問題が本当に状況に依存するかどうかは、潜在的な問題です。 –

+0

@TomKarzes:確かに、私は文字列の長さがわかっていない言語/環境で迷惑をかけることがありました。 :-) [wj32のソリューション](https://stackoverflow.com/a/4771055/157247)は、はるかに優れたパフォーマンスを提供します。 (非常に)大きな弦やタイトループの問題のみですが、重要な場合は重要です。 –

101

あり、このための標準的な機能はませんが、あなたは

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

を定義することができます私たちは、C規格に準拠したので、およそstrpreよりも短いことを心配する必要はありません(7.21.4.4/2):

strncmp関数s2で指される配列にs1によって指さ配列から(ヌル文字に続く文字が比較されていない)n文字以上でないと比較します。」

+4

なぜ答えはいいですか?明らかに、答えはyesです。これは 'strncmp'と呼ばれています。 – Jasper

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()機能を使用してください。私は生の実装おそらくstrncmp()で行くが、ちょうど楽しみのためにしたいStra == strstr(stra, strb)

+1

strbが接頭辞であるかどうかにかかわらず、非常に短い初期セグメントから明らかにすべきであるにもかかわらず、あなたは全体を通過するでしょう。 – StasM

22

:私が受け入れたバージョンを実行し、非常に長い列strに問題があったので

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

    return 1; 
} 
+6

私はこのベストが好きです。どちらかの文字列を長さでスキャンする理由はありません。 –

+1

私はおそらくstrlen + strncmpと一緒に行くでしょうが、実際には動作しますが、あいまいな定義を持つすべての論争が私を怒らせています。だから私はこれを使用します、ありがとう。 –

+4

glibcの作者は確かに:-) –

1

を、私はして追加する必要がありました次のロジック:

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

最適化(V.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; 
} 
+1

投票の否定: 'startsWith(" \ 2 "、" \ 1 ")'は1を返します。これは、 'strncmp'よりも遅くなる可能性があります。 'startsWith(" \ 1 "、" \ 1 ")'も1を返します – thejh

+0

あなたは正しいです。間違った行が1つありました。 – Zloten

+0

今よく見えます! :) – thejh

-5

最適化:

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

    return *s2 == 0; 
} 
+2

'StartsWith(" "、" ")'を試しましたか? – Neil

関連する問題