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
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.
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 alsn
-Zeichen (Zeichen, die einem Nullzeichen folgen, wird nicht verglichen) von dem Array, auf dass1
zeigt, mit dem Array, auf dass2
zeigt. "
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;
}
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;
}
Verwenden Sie die Funktion strstr()
. Stra == strstr(stra, strb)
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;
}
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;
}
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.