Как разобрать строку с пробелами в целое число - PullRequest
4 голосов
/ 09 августа 2010

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

Я рассматривал возможность использования strchr и strcat, например:

char* remove_spaces (char* s)
{
    char* space;
    while (space = strchr(s, ' '))
    {
        *space = '\0';
        strcat(s, space + 1);
    }

    return s;
}

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

Далее, мне интересно, можно ли это сделать лучше с чем-токак sscanf.

Ответы [ 6 ]

4 голосов
/ 09 августа 2010
char* trim (char* s)
{
    char* space;
    while (space = strchr(s, ' '))
    {
        memmove(space,space+1,strlen(space));
    }

    return s;
}
1 голос
/ 09 августа 2010

Альтернативный метод, основанный на Дэвиде Дивене:

void removeSpaces( char* str )
{
    char* input = str;
    char* output = str;
    for( ; *input != 0; ++input )
    {
        if( *input != ' ' )
            *output++ = *input;
    }
    *output = 0;
}

Я бы не беспокоился о проблемах производительности при использовании memmove, если ваши строки не очень большие. Для этого нет простого способа использовать sscanf, так как трудно определить, где во входной строке должен начинаться каждый вызов sscanf.

1 голос
/ 09 августа 2010

Для такой простой задачи обычно проще всего циклически перебирать символ за символом:

void trim(char* buffer)
{
    char* r = buffer;
    char* w = buffer;
    for (;;)
    {
        char c = *r++;
        if (c != ' ')
            *w++ = c;
        if (c == '\0')
            break;
    }
}

Безопасно использовать один и тот же буфер для чтения и записи, потому что мы знаем, что обрезанная строка всегда будеткороче оригинальной строки.Это самое быстрое из возможных решений, поскольку каждый символ читается один раз и записывается не более одного раза.

Вы не можете использовать strcpy (), когда источник и пункт назначения перекрываются - спецификация запрещает это.

Я не знаю о scanf ();внутри него скрыты всевозможные неясные, но полезные вещи, и стоит заглянуть в справочную страницу.

Отредактировано: исправлена ​​глупая опечатка, из-за которой она не работала.

1 голос
/ 09 августа 2010

Вы можете использовать strtok

//asuming line points to the beginning of your string

char *col_str = line, c;
short int *the_numbers;
int col, col_num, count = 0;
while((c = *col_str++) != '\0'){
    if(c == ' '){
        count++;
    }
}

the_numbers = (*short int)malloc(sizeof(short int)*count+1);

for(col_num = 0,col_str = line; ; col_num++,col_str = NULL){
    col = atoi(strtok(col_str, ' '));
    the_numbers[col_num] = (short int)col;
}

РЕДАКТИРОВАТЬ:

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

short int *the_numbers = (short int*)malloc(NUM_ITEMS * sizeof(short int));

Возможно, вы могли бы сделать это и с malloc и realloc, но я не уверен, что это будет быстрее.

0 голосов
/ 10 августа 2010

Вы можете использовать strtoul для преобразования без необходимости манипулирования строкой. Strtoul преобразует столько, сколько может, и говорит вам, где он остановился. Удобно, он также пропускает лидирующие пробелы. Итак:

static  unsigned long   conv( const char* s)
{   unsigned long   num, dig;
    char* endp;

    for(num=0;;s=endp)
    {      dig = strtoul( s, &endp, 10);
            if ( s == endp)
            {   break;
            }
            num = num*1000 + dig;
    }
    return num;
}
0 голосов
/ 09 августа 2010

Нет, использование strcat небезопасно (§7.21.3.1 / 2: «Если копирование происходит между перекрывающимися объектами, поведение не определено.»)

Если вы немного поищите, вы можете найти несколько десятков (или более) реализаций этого в Интернете ( один пример ).

...