如何将带有空格的字符串解析为整数

4

我有一个表示带空格的整数的字符串 -- 数字以三个一组分组。

我考虑使用 strchrstrcat,例如:

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

    return s;
}

但是首先,我不确定这种方式使用strcat是否安全,因为要附加的字符串与最终字符串重叠。
接下来,我想知道是否可以用类似sscanf的东西更好地完成这个任务。

trim建议从字符串的开头或结尾删除字符,我会将您的函数重命名为removeSpaces()或类似名称。 - Patrick
我正在考虑一种基于特殊区域设置的解决方案,其中小数分隔符设置为空格。我没有时间尝试它,所以如果有人想赚取一些声望...请前进! - Sjoerd
请举一个字符串的例子,并说明您期望得到什么输出。 - Martin York
6个回答

4
char* trim (char* s)
{
    char* space;
    while (space = strchr(s, ' '))
    {
        memmove(space,space+1,strlen(space));
    }

    return s;
}

1
这不会非常低效吗?因为需要重复读写字符串的后面部分。 - David Given

1
你可以使用 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来实现这个,但我不确定那样是否更快。

这正是我要建议的。 - James
1
我认为这并不是作者所询问的 --- col 最终只会包含数字的最后一个子句的数值吧? - David Given
他需要将它们存储在一个整数数组中,我想我应该包括这部分。 - GWW

1

对于这种简单的问题,通常最容易的方法就是逐个字符地循环:

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

使用同一个缓冲区进行读写是安全的,因为我们知道修剪后的字符串始终比原始字符串要短。这是最快的解决方案,因为每个字符仅被读取一次,并且最多只写入一次。

当源和目标重叠时,不能使用strcpy() --- 规范禁止使用它。

我不了解scanf(); 在其中有各种晦涩但有用的内容,值得仔细阅读man页。

编辑:修复了愚蠢的拼写错误,现在可以正常工作了。


1
一种基于David Given的替代方法:
void removeSpaces( char* str )
{
    char* input = str;
    char* output = str;
    for( ; *input != 0; ++input )
    {
        if( *input != ' ' )
            *output++ = *input;
    }
    *output = 0;
}

我不会担心使用memmove的性能问题,除非你的字符串真的很大。使用sscanf并不容易实现这一点,因为很难定义每次调用sscanf在输入字符串中应该从哪里开始。

我接受了gordongekko的答案,因为字符串长度不足以影响性能,但我真的很喜欢你的答案! - parras

0
你可以使用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
不,你使用的 strcat 不安全 (§7.21.3.1/2: "如果在重叠对象之间进行复制,则行为未定义。")

如果你仔细搜索一下,可能可以在网上找到几十个(或更多)此类实现 (一个例子)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接