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

Lesezeit: 5 Minuten

Benutzeravatar von thejh
diejh

Gibt es sowas startsWith(str_a, str_b) in der Standard-C-Bibliothek?

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

Beispiele:

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

  • Ich denke, Ihr 3. Beispiel sollte ein wahres Ergebnis haben.

    – Michael Burr

    23. Januar 2011 um 6:19 Uhr

  • mögliches Duplikat von stackoverflow.com/questions/15515088/…

    – Urlaub

    15. Oktober 2019 um 6:52 Uhr

Benutzeravatar von Fred Foo
Fred Fu

Dafür gibt es keine Standardfunktion, aber Sie können sie definieren

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

Wir müssen uns keine Sorgen machen str kürzer sein als pre denn laut C-Standard (7.21.4.4/2):

Das strncmp Funktion vergleicht nicht mehr als n Zeichen (Zeichen, die einem Nullzeichen folgen, werden nicht verglichen) aus dem Array, auf das gezeigt wird s1 zu dem Array, auf das von gezeigt wird s2.”

  • Warum ist die Antwort nein? Ganz klar, die Antwort ist ja, es heißt strncmp.

    – Jaspis

    13. Februar 2017 um 0:39 Uhr


  • ^ Es sollte offensichtlich sein, warum die Antwort nein ist. Ein Algorithmus, der verwendet strncmp und strlen heißt nicht “strncmp”.

    – Jim Balter

    1. August 2019 um 18:50 Uhr

Anscheinend 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 : memcmp(pre, str, lenpre) == 0;
}

Beachten Sie, dass das Obige schön und klar ist, aber wenn Sie es in einer engen Schleife tun oder mit arbeiten sehr großen Saiten bietet es nicht die beste Leistung, da es die volle Länge beider Saiten vorne abtastet (strlen). Lösungen wie die von wj32 oder Christoph bieten möglicherweise eine bessere Leistung (obwohl dieser Kommentar zur Vektorisierung außerhalb meines Verständnisses von C liegt). Beachten Sie auch die Lösung von Fred Foo, die vermeidet strlen an str (Er hat Recht, es ist unnötig, wenn Sie verwenden strncmp Anstatt von memcmp). Ist nur wichtig für (sehr) große Saiten oder wiederholte Verwendung in engen Schleifen, aber wenn es darauf ankommt, ist es wichtig.

  • Ich sollte erwähnen, dass die üblich Die Sache wäre, dass die Zeichenfolge der erste Parameter ist und das Präfix für den zweiten. Aber ich habe sie wie oben beibehalten, weil Ihre Frage anscheinend so formuliert war … Die Reihenfolge liegt ganz bei Ihnen, aber ich hätte es wirklich andersherum machen sollen – die meisten Zeichenfolgenfunktionen nehmen die vollständige Zeichenfolge als erstes Argument, der Teilstring als zweites.

    – TJ Crowder

    22. Januar 2011 um 22:31 Uhr

  • Dies ist eine elegante Lösung, die jedoch einige Leistungsprobleme aufweist. Eine optimierte Implementierung würde niemals mehr als min(strlen(pre), strlen(str)) Zeichen aus jeder Zeichenfolge betrachten, noch würde sie jemals über die erste Nichtübereinstimmung hinausgehen. Wenn die Saiten lang wären, aber frühe Fehlanpassungen üblich wären, wäre es sehr leicht. Da diese Implementierung jedoch die volle Länge beider Zeichenfolgen im Voraus verwendet, erzwingt sie eine Worst-Case-Leistung, selbst wenn sich die Zeichenfolgen im allerersten Zeichen unterscheiden. Ob dies wirklich wichtig ist, hängt von den Umständen ab, aber es ist ein potenzielles Problem.

    – Tom Karzes

    6. Januar 2018 um 11:33 Uhr


  • @TomKarzes Sie können ersetzen memcmp zum strncmp hier und es ist schneller. Es gibt kein UB, weil beide Saiten bekanntermaßen mindestens haben lenpre Byte. strncmp prüft jedes Byte beider Strings auf NUL, aber die strlen Anrufe schon garantiert, dass es keine gibt. (Aber es hat immer noch den von Ihnen erwähnten Leistungseinbruch, wenn pre oder str sind länger als die eigentliche gemeinsame Anfangssequenz.)

    – Jim Balter

    1. August 2019 um 18:43 Uhr


  • @JimBalter – Sehr guter Punkt! Seit der Verwendung memcmp oben würde sich hier nicht von einer anderen Antwort aneignen, ich habe es in der Antwort geändert.

    – TJ Crowder

    2. August 2019 um 6:46 Uhr


  • PS Dies ist (jetzt) ​​möglicherweise die schnellste Antwort auf einigen Maschinen mit einigen Zeichenfolgen, weil strlen und memcmp kann mit sehr schnellen Hardwareanweisungen implementiert werden, und die strlens kann die Zeichenfolgen in den Cache stellen, wodurch ein doppelter Speichertreffer vermieden wird. Auf solchen Maschinen strncmp könnte als zwei implementiert werden strlens und a memcmp einfach so, aber es wäre für einen Bibliotheksautor riskant, dies zu tun, da dies bei langen Zeichenfolgen mit kurzen gemeinsamen Präfixen viel länger dauern könnte. Hier ist dieser Treffer explizit und der strlens werden jeweils nur einmal durchgeführt (Fred Foo’s strlen + strncmp würde machen 3).

    – Jim Balter

    2. August 2019 um 17:06 Uhr


Benutzeravatar von Christoph
Christoph

Ich würde wahrscheinlich mitgehen strncmp()aber nur zum Spaß eine rohe Implementierung:

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

    return 1;
}

  • Das gefällt mir am besten – es gibt keinen Grund, eine der Saiten nach einer Länge zu scannen.

    – Michael Burr

    23. Januar 2011 um 6:22 Uhr

  • Ich würde wahrscheinlich auch mit strlen+strncmp gehen, aber obwohl es tatsächlich funktioniert, schreckt mich die ganze Kontroverse über seine vage Definition ab. Also werde ich das verwenden, danke.

    – Sam Watkins

    6. Januar 2015 um 3:26 Uhr

  • Dies ist wahrscheinlich langsamer als strncmpes sei denn, Ihr Compiler ist wirklich gut in der Vektorisierung, weil Glibc-Autoren das sicher sind 🙂

    – Ciro Santilli OurBigBook.com

    27. Juni 2015 um 12:39 Uhr


  • Diese Version sollte schneller sein als die strlen+strncmp-Version, wenn das Präfix nicht übereinstimmt, insbesondere wenn es bereits Unterschiede in den ersten Zeichen gibt.

    – dpi

    14. Juli 2018 um 0:22 Uhr

  • ^ Diese Optimierung würde nur gelten, wenn die Funktion eingebettet ist.

    – Jim Balter

    2. August 2019 um 17:48 Uhr

gscotts Benutzeravatar
gscott

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

Ich bin kein Experte darin, eleganten Code zu schreiben, 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;
}

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

Benutzeravatar von Jordan
Jordanien

Da ich die akzeptierte Version ausgeführt habe und ein Problem mit einer sehr langen Zeichenfolge hatte, musste ich die 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;
}

1421550cookie-checkWie überprüfe ich, ob eine Zeichenfolge mit einer anderen Zeichenfolge in C beginnt?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy