web-dev-qa-db-ja.com

文字列がCの別の文字列で始まるかどうかを確認するにはどうすればよいですか?

標準CライブラリにはstartsWith(str_a, str_b)のようなものがありますか?

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

例:

"abc", "abcdef" -> true
"abcdef", "abc" -> false
"abd", "abdcef" -> true
"abc", "abc"    -> true
69
thejh

これには標準のC関数はないようです。そう:

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

上記はナイスで明確ですが、タイトなループで実行している場合、またはvery大きな文字列で作業している場合、両方の文字列の全長(strlen)をスキャンするため、最高のパフォーマンス。 wj32'sChristoph's のようなソリューションは、より良いパフォーマンスを提供するかもしれません(ただし、 このコメント ベクトル化については私のCの範囲を超えています)。また注意してください Fred Fooの解 これはstrlenstrを回避します(そうです、strncmpの代わりにmemcmpを使用する場合は不要です) )。 (非常に)大きな文字列またはタイトループで繰り返し使用する場合にのみ問題になりますが、問題になる場合は重要です。

62
T.J. Crowder

これには標準機能はありませんが、定義できます

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

C標準(7.21.4.4/2)によると、strpreより短いことを心配する必要はありません。

strncmp関数は、s1が指す配列からs2が指す配列とn文字以下を比較します(ヌル文字に続く文字は比較されません)。

124
Fred Foo

おそらくstrncmp()を使用しますが、ただの楽しみのために生の実装を使用します。

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

    return 1;
}
30
Christoph

私はエレガントなコードを書くのに精通していませんが...

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;
}
5
wj32

strstr()関数を使用します。 Stra == strstr(stra, strb)

5
gscott

最適化(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;
}
2
Zloten

受け入れられたバージョンを実行し、非常に長い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
Jordan

または、2つのアプローチの組み合わせ:

_Bool starts_with(const char *restrict string, const char *restrict prefix)
{
    char * const restrict prefix_end = prefix + 13;
    while (1)
    {
        if ( 0 == *prefix  )
            return 1;   
        if ( *prefix++ != *string++)
            return 0;
        if ( prefix_end <= prefix  )
            return 0 == strncmp(prefix, string, strlen(prefix));
    }  
}

編集:以下のコードは[〜#〜] not [〜#〜]動作します。strncmpが0を返す場合、終端の0または長さ(block_size )に達しました。

追加のアイデアは、ブロックごとに比較することです。ブロックが等しくない場合、そのブロックを元の関数と比較します。

_Bool starts_with_big(const char *restrict string, const char *restrict prefix)
{
    size_t block_size = 64;
    while (1)
    {
        if ( 0 != strncmp( string, prefix, block_size ) )
          return starts_with( string, prefix);
        string += block_size;
        prefix += block_size;
        if ( block_size < 4096 )
          block_size *= 2;
    }
}

定数13644096、およびblock_sizeのべき乗は単なる推測です。使用する入力データとハードウェアに対して選択する必要があります。

1
shpc