webentwicklung-frage-antwort-db.com.de

Wie prüfe ich, ob eine Zeichenfolge mit einer anderen Zeichenfolge in C beginnt?

Gibt es so etwas wie startsWith(str_a, str_b) in der Standard-C-Bibliothek?

Es sollte Zeiger auf zwei Zeichenfolgen bringen, die mit Nullbytes enden, und sagen, ob der erste vollständig am Anfang des zweiten steht.

Beispiele:

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

Offenbar gibt es dafür keine Standard-C-Funktion. So:

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

Beachten Sie, dass das oben genannte „Nice and clear“ ist. Wenn Sie dies jedoch in einer engen Schleife tun oder mit very großen Saiten arbeiten, bietet es möglicherweise nicht die beste Leistung, da es die volle Länge beider Saiten abtastet (strlen). Lösungen wie wj32s oder Christophs können eine bessere Leistung bieten (obwohl dieser Kommentar über Vektorisierung liegt außerhalb meines Wissensbereiches C). Beachten Sie auch die Lösung von Fred Foo , die strlen auf str vermeidet (er hat Recht, es ist unnötig). Nur für (sehr) große Saiten oder wiederholte Verwendung in engen Loops, aber wenn es darauf ankommt, ist es wichtig.

58
T.J. Crowder

Es gibt keine Standardfunktion dafür, aber Sie können definieren

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

Wir müssen uns keine Sorgen darüber machen, dass str kürzer ist als pre, weil laut C-Standard (7.21.4.4/2):

Die strncmp-Funktion vergleicht nicht mehr als n-Zeichen (Zeichen, die einem Nullzeichen folgen, wird nicht verglichen) von dem Array, auf das s1 zeigt, mit dem Array, auf das s2 zeigt. "

118
Fred Foo

Ich würde wahrscheinlich mit strncmp() gehen, aber nur zum Spaß eine reine Implementierung:

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

    return 1;
}
25
Christoph

Ich bin kein Experte für das Schreiben von elegantem Code, aber ...

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

Verwenden Sie die Funktion strstr(). Stra == strstr(stra, strb)

5
gscott

Optimiert (V.2. - korrigiert):

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

Da ich die akzeptierte Version lief und ein Problem mit einem sehr langen str hatte, musste ich folgende Logik hinzufügen:

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

Oder eine Kombination der beiden Ansätze:

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

Eine weitere Idee ist, blockweise zu vergleichen. Wenn der Block nicht gleich ist, vergleichen Sie diesen Block mit der ursprünglichen Funktion:

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

Die Konstanten 13, 64, 4096 sowie die Potenzierung des block_size sind nur Vermutungen. Es müsste für die verwendeten Eingangsdaten und Hardware ausgewählt werden.

0
shpc