Как проверить, начинается ли строка с другой строки в C? - PullRequest
69 голосов
/ 23 января 2011

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

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

Примеры:

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

Ответы [ 9 ]

123 голосов
/ 23 января 2011

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

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

62 голосов
/ 23 января 2011

Очевидно, для этого нет стандартной функции 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 или Christoph , могут предложить более высокую производительность (хотя этот комментарий о векторизации выходит за рамки моего понимания языка C). Также обратите внимание на решение Фреда Фу , которое избегает strlen на str (он прав, в этом нет необходимости). Имеет значение только для (очень) больших струн или повторного использования в тесных петлях, но когда это имеет значение, это имеет значение.

28 голосов
/ 23 января 2011

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

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

    return 1;
}
5 голосов
/ 23 января 2011

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

5 голосов
/ 23 января 2011

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

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;
}
1 голос
/ 05 ноября 2014

Оптимизировано (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;
}
1 голос
/ 26 октября 2014

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

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;
}
0 голосов
/ 19 сентября 2018

Или комбинация двух подходов:

_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 - всего лишь догадки,Он должен быть выбран для используемых входных данных и аппаратного обеспечения.

0 голосов
/ 08 февраля 2015

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

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

  return *s2 == 0;
}
...