2010-08-09 108 views
4

我有一个字符串表示一个整数与空格 - 数字分为三。如何用空格解析字符串到整数

我用strchrstrcat,如考虑:

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

    return s; 
} 

但是,第一,我不知道它是安全的使用strcat这种方式,因为要追加字符串重叠,最后一个字符串。

接下来,我想知道这是否可以用sscanf之类的东西做得更好。

+0

装饰表明,字符正在从字符串开始处或结束修整,我会重命名功能removeSpaces()或类似 – Patrick 2010-08-09 15:15:39

+0

这是正确的!我纠正了。 – 2010-08-10 07:06:29

+0

我正在考虑基于特殊区域设置的解决方案,将decimal_separator设置为空格。我没有时间去尝试,所以如果有人想得到一些代表...继续前进! – Sjoerd 2010-08-10 07:08:30

回答

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

    return s; 
} 
+1

由于反复读写字符串的后续部分,这不是真的效率低下吗? – 2010-08-09 15:12:54

+0

表现不是问题 – user411313 2010-08-09 16:47:15

0

不,你的strcat使用并不安全(§7.21.3.1/ 2:“如果进行复制操作是重叠的对象之间,行为是不确定的。”)

如果你做一点看,你可能会在网上找到几十个(或更多)这个实现(one example)。

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做到这一点,但我不确定这是否会更快。

+0

这就是我正在建议的。 – James 2010-08-09 15:14:07

+1

我不认为这是作者所问的---不是最终会包含数字的最后一个子句的数字值吗? – 2010-08-09 15:14:58

+0

他将不得不将它们存储在整数数组中,我想我应该包含该部分 – GWW 2010-08-09 15:15:40

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();有各种各样的晦涩而有用的东西埋在它的内部,值得通过手册页。

编辑:修复了愚蠢的错字,这意味着它没有工作。鉴于

+0

-1这实际上并不改变缓冲区的内容 – Patrick 2010-08-09 15:38:10

+0

D'oh!你是对的。固定。 – 2010-08-09 15:58:35

+0

-1已删除,并刚刚添加了我自己的想法 – Patrick 2010-08-09 16:04:17

1

根据大卫的另一种方法的:

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

我不会担心使用的memmove的性能问题,除非你的字符串是真正的大。有没有一种简单的方法来使用sscanf,因为很难定义每个调用sscanf的输入字符串应该在哪里开始。

+0

我接受gordongekko的答案,因为字符串足够短不会影响性能,但我真的很喜欢你的! – 2010-08-10 07:29:53

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