Почему подстрока не является частью стандартной библиотеки C? - PullRequest
2 голосов
/ 13 сентября 2011

Я знаю, что C преднамеренно пустая, но мне любопытно, почему что-то столь обычное, как функция подстроки, не включено в .

Неужели нет одного "достаточно правильного" способа сделать это? Слишком много специфичных для домена требований? Кто-нибудь может пролить свет?

Кстати, это функция подстроки, с которой я столкнулся после небольшого исследования. Изменить: Я сделал несколько обновлений на основе комментариев.

void substr (char *outStr, const char *inpStr, int startPos, size_t strLen) {
    /* Cannot do anything with NULL. */
    if (inpStr == NULL || outStr == NULL) return;

    size_t len = strlen (inpStr);

    /* All negative positions to go from end, and cannot
    start before start of string, force to start. */
    if (startPos < 0) {
        startPos = len + startPos;
    }
    if (startPos < 0) {
        startPos = 0;
    }

    /* Force negative lengths to zero and cannot
    start after end of string, force to end. */
    if ((size_t)startPos > len) {
        startPos = len;
    }

    len = strlen (&inpStr[startPos]);
    /* Adjust length if source string too short. */
    if (strLen > len) {
        strLen = len;
    }

    /* Copy string section */
    memcpy(outStr, inpStr+startPos, strLen);
    outStr[strLen] = '\0';
}

Редактировать: На основании комментария от r я также придумал этот лайнер. Ты сам по себе для проверок, хотя!

#define substr(dest, src, startPos, strLen) snprintf(dest, BUFF_SIZE, "%.*s", strLen, src+startPos)

Ответы [ 6 ]

6 голосов
/ 13 сентября 2011

Основные функции стандартной библиотеки не обременяют себя чрезмерно дорогими проверками безопасности, оставляя их пользователю. Большинство проверок безопасности, которые вы выполняете в своей реализации, являются дорогостоящими: совершенно неприемлемо в такой базовой библиотечной функции. Это C, а не Java.

Как только вы получаете некоторые проверки из картинки, функция «подстегнуть» сводится к обычному strlcpy. Т.е. игнорируя проверку безопасности на startPos, все, что вам нужно сделать, это

char *substr(const char *inpStr, char *outStr, size_t startPos, size_t strLen) {
  strlcpy(outStr, inpStr + startPos, strLen);
  return outStr;
}

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

char *substr(const char *inpStr, char *outStr, size_t startPos, size_t strLen) {
  strncpy(outStr, inpStr + startPos, strLen);
  outStr[strLen] = '\0';
  return outStr;
}

Как ни странно, в вашем коде strncpy неправильно используется точно так же. Кроме того, многие из ваших проверок безопасности являются прямым следствием того, что вы выбрали тип со знаком (int) для представления индексов, тогда как правильный тип будет беззнаковым (size_t).

3 голосов
/ 13 сентября 2011

Возможно, потому что это однострочный:

snprintf(dest, dest_size, "%.*s", sub_len, src+sub_start);
2 голосов
/ 13 сентября 2011

У вас есть strcpy и strncpy.Тебе не достаточно?С strcpy вы можете смоделировать подстроку от символа к концу, с strncpy вы можете смоделировать подстроку из символа для количества символов (вам нужно только не забыть добавить \0 в конце строки).strncpy даже лучше, чем эквивалент C #, потому что вы можете перескочить длину подстроки, и она не выдаст ошибку (если вы выделили достаточно места в dest, вы можете сделать strncpy(dest, src, 1000), даже если src long 1В C # вы не можете. Как написано в комментарии, вы даже можете использовать memcpy, но не забывайте всегда добавлять \0 в конце строки, и вы должны знать, сколько символов вы копируете (поэтому вы должны знать точно длину подстроки src) И это немного сложнее использовать, если в день вы хотите реорганизовать свой код для использования wchar_t И это не безопасно для типов (потому что он принимает void *вместо символа *).Все это в обмен на немного большую скорость за strncpy

0 голосов
/ 17 июля 2014
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const char* substr(const char *string, size_t from, size_t to);

int main(int argc, char *argv[])
{
    char *string = argv[1];

    const char *substring = substr(string,6,80);

    printf("string is [%s] substring is [%s]\n",string,substring);

    return 0;
}

const char* substr(const char *string, size_t from, size_t to)
{
    if (to <= from) 
        return NULL;

    if (from >= to)
        return NULL;

    if (string == NULL)
        return NULL;

    if (strlen(string) == 0)
        return NULL;

    if (from < 0)
        from = 0;

    if (to > strlen(string))
        to = strlen(string);

    char *substring = malloc(sizeof(char) * ((to-from)+1));

    size_t index;

    for (index = 0; from < to; from++, index++)
        substring[index] = string[from];

    substring[index] = '\0';

    return substring;
}
0 голосов
/ 13 сентября 2011

В C у вас есть функция, которая возвращает подмножество символов из строки с помощью указателей: strstr .

char *ptr;
char string1[] = "Hello World";
char string2[] = "World";

ptr = strstr(string1, string2)

* ptr будет указывать на появление первого символа.

Кстати, вы написали не функцию, а процедуру, строковые функции ANSI: string.h

0 голосов
/ 13 сентября 2011

Вот облегченная версия того, что вы хотите.Избегает избыточных вызовов strlen и гарантирует нулевое завершение в буфере назначения (чего-то, что strncpy не сделает).

void substr(char* pszSrc, int start, int N, char* pszDst, int lenDest)
{
    const char* psz = pszSrc + start;
    int x = 0;

    while ((x < N) && (x < lenDest))
    {
        char ch = psz[x];
        pszDst[x] = ch;
        x++;
        if (ch == '\0')
        {
           return;
        }
    }

    // guarantee null termination
    if (x > 0)
    {    
        pszDest[x-1] = 0;
    }
}

Example:
char *pszLongString = "This is a long string";
char szSub[10];
substr(pszLongString, 0, 4, szSub, 10); // copies "long" into szSub and includes the null char

Таким образом, хотя в C нет формальной функции подстроки, классы строк C ++ обычно имеют такиеметод:

#include <string>
...
std::string str;
std::string strSub;

str = "This is a long string";

strSub = str.substr(10, 4); // "long"

printf("%s\n", strSub.c_str());
...