Подтвердить что ты не робот

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

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

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

Примеры:

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

Ответ 1

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

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

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

Ответ 2

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

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. "

Ответ 3

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

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

    return 1;
}

Ответ 4

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

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

Ответ 5

Используйте функцию strstr(). Stra == strstr(stra, strb)

Ответ 6

Оптимизировано (v.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;
}

Ответ 7

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

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

Ответ 8

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

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

ОБНОВЛЕНИЕ: Приведенный ниже код работает НЕ, потому что если strncmp возвращает 0, неизвестно, был ли достигнут завершающий 0 или длина (block_size).

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

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

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

Ответ 9

Оптимизированный:

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

  return *s2 == 0;
}