web-dev-qa-db-fra.com

Comment vérifier si une chaîne commence par une autre chaîne en C?

Existe-t-il quelque chose comme startsWith(str_a, str_b) dans la bibliothèque standard C?

Cela devrait prendre des pointeurs sur deux chaînes qui se terminent par nullbytes et me dire si la première apparaît également complètement au début de la seconde.

Exemples:

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

Apparemment, il n’ya pas de fonction C standard pour cela. Alors:

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

Notez que ce qui précède est beau et clair, mais si vous le faites dans une boucle serrée ou si vous travaillez avec très grosses chaînes, il se peut que la performance ne soit pas optimale car il scanne toute la longueur des deux chaînes à l'avant (strlen). Des solutions comme wj32 ou Christoph peuvent offrir de meilleures performances (bien que ce commentaire à propos de la vectorisation est au-dessus de mes connaissances de C). Notez aussi La solution de Fred Foo qui évite strlen sur str (il a raison, c'est inutile). Ne concerne que les chaînes (très) volumineuses ou les utilisations répétées dans des boucles serrées, mais lorsque c'est important, c'est important.

58
T.J. Crowder

Il n'y a pas de fonction standard pour cela, mais vous pouvez définir

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

Nous n'avons pas à nous soucier de str étant plus court que pre car, selon la norme C (7.21.4.4/2):

La fonction strncmp ne compare pas plus de n caractères (les caractères qui suivent un caractère nul ne sont pas comparés) du tableau pointé par s1 au tableau pointé par s2. "

118
Fred Foo

J'irais probablement avec strncmp(), mais juste pour le plaisir, une implémentation brute:

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

    return 1;
}
25
Christoph

Je ne suis pas un expert en écriture de code élégant, mais ...

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

Utilisez la fonction strstr(). Stra == strstr(stra, strb)

5
gscott

Optimisé (v.2. - corrigé):

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
Zloten

Parce que je courais la version acceptée et que je rencontrais un problème avec une très longue chaîne, j'ai dû ajouter la logique suivante:

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

Ou une combinaison des deux approches:

_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));
    }  
}

Une autre idée est de comparer les blocs. Si le bloc n'est pas égal, comparez ce bloc avec la fonction d'origine:

_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);
        if ( block_size < 4096 )
          block_size *= 2;
        string += block_size;
        prefix += block_size;
    }
}

Les constantes 13, 64, 4096 ainsi que l’exponentiation de block_size ne sont que des suppositions. Il devrait être sélectionné pour les données d'entrée et le matériel utilisés.

0
shpc