Gibt es so etwas wie startsWith(str_a, str_b)
in der Standard-C-Bibliothek?
Es sollte Zeiger auf zwei Zeichenfolgen enthalten, die mit null Bytes enden, und mir sagen, ob die erste auch am Anfang der zweiten vollständig angezeigt wird.
Beispiele:
"abc", "abcdef" -> true
"abcdef", "abc" -> false
"abd", "abdcef" -> true
"abc", "abc" -> true
c
string
comparison
startswith
thejh
quelle
quelle
Antworten:
Anscheinend gibt es dafür keine Standard-C-Funktion. Damit:
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 oben Genannte schön und klar ist. Wenn Sie es jedoch in einer engen Schleife ausführen oder mit sehr großen Saiten arbeiten, bietet es nicht die beste Leistung, da es die gesamte Länge beider Saiten vorne abtastet (
strlen
). Lösungen wie wj32 oder Christoph bieten möglicherweise eine bessere Leistung (obwohl dieser Kommentar zur Vektorisierung jenseits meines Wissens von C liegt). Beachten Sie auch , Fred Foo-Lösung , die vermeidetstrlen
aufstr
(er ist richtig, es ist nicht notwendig , wenn Sie verwendenstrncmp
stattmemcmp
). Nur wichtig für (sehr) große Saiten oder wiederholte Verwendung in engen Schleifen, aber wenn es darauf ankommt, ist es wichtig.quelle
memcmp
fürstrncmp
hier und es ist schneller. Es gibt keine UB, da bekannt ist, dass beide Zeichenfolgen mindestenslenpre
Bytes haben.strncmp
Überprüft jedes Byte beider Zeichenfolgen auf NUL, aber diestrlen
Aufrufe haben bereits garantiert, dass keine vorhanden sind. (Aber es hat immer noch den Performance-Hit, den Sie erwähnt haben, wennpre
oderstr
länger als die eigentliche gemeinsame Anfangssequenz.)memcmp
obigen Informationen hier nicht für eine andere Antwort geeignet wäre, habe ich sie in der Antwort geändert.strlen
undmemcmp
kann mit sehr schnellen Hardware-Anweisungen umgesetzt werden, und diestrlen
s die Saiten in die Cache stellen kann, einen doppelten Speichertreffer zu vermeiden. Auf solchen Maschinenstrncmp
könnte dies als zweistrlen
Sekunden undmemcmp
genau so implementiert werden , aber es wäre für einen Bibliotheksschreiber 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 diestrlen
s werden jeweils nur einmal ausgeführt (Fred Foo'sstrlen
+strncmp
würde 3 ausführen ).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 machen,
str
dass wir kürzer sind alspre
nach dem C-Standard (7.21.4.4/2):quelle
strncmp
.strncmp
undstrlen
nicht "strncmp" heißt.Ich würde wahrscheinlich mitmachen
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; }
quelle
strncmp
, es sei denn, Ihr Compiler ist wirklich gut in der Vektorisierung, denn glibc-Autoren sind sicher :-)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; }
quelle
Verwenden Sie
strstr()
Funktion.Stra == strstr(stra, strb)
quelle
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; }
quelle
startsWith("\2", "\1")
gibt 1 zurück, gibtstartsWith("\1", "\1")
auch 1 zurückDa ich die akzeptierte Version ausgeführt habe und ein Problem mit einem sehr langen Str 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; }
quelle
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)); } }
BEARBEITEN: Der folgende Code funktioniert NICHT , da wenn strncmp 0 zurückgibt, nicht bekannt ist, ob eine abschließende 0 oder die Länge (block_size) erreicht wurde.
Eine weitere Idee ist der blockweise Vergleich. 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); string += block_size; prefix += block_size; if ( block_size < 4096 ) block_size *= 2; } }
Die Konstanten
13
,64
,4096
sowie die Potenzierung derblock_size
nur Vermutungen. Es müsste für die verwendeten Eingabedaten und Hardware ausgewählt werden.quelle
block_size
Inkrementierung muss nach der Zeigerinkrementierung erfolgen. Jetzt behoben.