resueltos - ¿Cómo comprobar si una cadena comienza con otra cadena en C?
funciones de cadenas de caracteres en c++ (9)
¿Hay algo como startsWith(str_a, str_b)
en la biblioteca estándar de C?
Debería llevar los punteros a dos cadenas que terminan con nullbytes y decirme si la primera también aparece completamente al comienzo de la segunda.
Ejemplos:
"abc", "abcdef" -> true
"abcdef", "abc" -> false
"abd", "abdcef" -> true
"abc", "abc" -> true
Aparentemente no hay una función estándar de C para esto. Asi que:
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;
}
Tenga en cuenta que lo anterior es agradable y claro, pero si lo está haciendo en un circuito cerrado o trabajando con cadenas muy grandes, es posible que no ofrezca el mejor rendimiento, ya que explora toda la longitud de ambas cadenas en la parte delantera ( strlen
). Soluciones como wj32''s o Christoph''s pueden ofrecer un mejor rendimiento (aunque este comentario sobre la vectorización está más allá de mi conocimiento de C). También tenga en cuenta la solución de Fred Foo que evita strlen
en str
(tiene razón, es innecesario). Solo importa para cuerdas (muy) grandes o uso repetido en bucles ajustados, pero cuando importa, importa.
Como ejecuté la versión aceptada y tuve un problema con una cadena muy larga, tuve que agregar la siguiente lógica:
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;
}
No hay una función estándar para esto, pero puede definir
bool prefix(const char *pre, const char *str)
{
return strncmp(pre, str, strlen(pre)) == 0;
}
No tenemos que preocuparnos por que str
sea más corto que el pre
porque, según el estándar C (7.21.4.4/2):
La función
strncmp
no compara más den
caracteres (los caracteres que siguen a un carácter nulo no se comparan) de la matriz apuntada pors1
a la matriz apuntada pors2
".
No soy un experto en escribir código elegante, pero ...
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;
}
O una combinación de los dos enfoques:
_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));
}
}
Una idea adicional es comparar el bloque. Si el bloque no es igual, compare ese bloque con la función original:
_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;
}
}
Las constantes 13
, 64
, 4096
, así como la exponenciación del block_size
de block_size
son solo suposiciones. Debería seleccionarse para los datos de entrada y el hardware utilizados.
Optimizado (v.2. - corregido):
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;
}
Optimizado
boolean StartsWith(char *s1, char *s2)
{
while (*s1++ == *s2++)
{
}
return *s2 == 0;
}
Probablemente iría con strncmp()
, pero solo por diversión, una implementación en bruto:
_Bool starts_with(const char *restrict string, const char *restrict prefix)
{
while(*prefix)
{
if(*prefix++ != *string++)
return 0;
}
return 1;
}
Utilice la función strstr()
. Stra == strstr(stra, strb)