Как проверить, если строка начинается с другой строки в C?

есть что-то вроде startsWith(str_a, str_b) в стандартной библиотеке C?

это должно занять указатели на две строки, которые заканчиваются nullbytes, и скажите мне, появляется ли первый также полностью в начале второго.

примеры:

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

9 ответов


видимо нет стандартной функции C для этого. Итак:

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

обратите внимание, что выше хорошо и ясно, но если вы делаете это в узком цикле или работаете с очень большой строк, он не может предложить лучшую производительность, так как он сканирует всю длину обеих строк фронт (strlen). Решения типа wj32 это или Кристофа может предложить лучшую производительность (хотя комментарий о векторизации не Кен с). Также обратите внимание решение Фреда Фу, который избегает strlen on str (он прав, в этом нет необходимости). Имеет значение только для (очень) больших строк или повторного использования в узких петлях, но когда это имеет значение, это имеет значение.


для этого нет стандартной функции, но вы можете определить

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

нам не нужно беспокоиться о str меньше pre потому что согласно стандарту C (7.21.4.4/2):

на strncmp функция сравнивает не больше чем n символы (символы, следующие за нулевым символом не сравнить) из массива, на который указывает s1 в массиве, на который указывает s2."


Я бы, наверное, пойти с strncmp(), но просто для удовольствия сырой реализации:

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

    return 1;
}

Я не эксперт в написании элегантного кода, но...

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

использовать . Stra == strstr(stra, strb)


поскольку я запустил принятую версию и имел проблему с очень длинным str, мне пришлось добавить следующую логику:

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

оптимизирован (В. 2. - исправлено):

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

или сочетание двух подходов:

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

дополнительная идея состоит в том, чтобы сравнить блок-мудрый. Если блок не равен, сравните этот блок с исходной функцией:

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

константы 13, 64, 4096, а также возведение в степень block_size просто догадки. Он должен быть выбран для используемых входных данных и оборудования.


оптимизирован:

boolean StartsWith(char *s1, char *s2)
{
  while (*s1++ == *s2++)
  {
  }

  return *s2 == 0;
}