从字符串中读取数字列表

时间:2014-11-03 22:04:01

标签: c stringstream scanf string-parsing

我想读一个以字符串形式存储的以空格分隔的数字列表 我知道如何在C ++中使用stringstream来实现这一点 -

string s = "10 22 45 67 89";
stringstream ss(s);
int numbers[100];
int k=0, next_number;
while(ss>>next_number)
    numbers[k++]=next_number;

我的问题是我们怎样才能在C中做到这一点? 我在C中读到了sscanf(),但我不确定它在这里是否有用。

5 个答案:

答案 0 :(得分:6)

使用sscanf()"%n了解下次扫描的开始位置。

char *s = "10 22 45 67 89";
for (k=0; k<100; k++) {
  int n;
  int cnt = sscanf(s, "%d %n", numbers[k], &n);
  if (cnt != 1) break;
  s += n;
}
if (*s) Handle_DidNotEndCleanly();

答案 1 :(得分:5)

如果你知道字符串中你期望的项目数,可以在这里使用sscanf

char const *s = "10 22 45 67 89";

sscanf(s, "%d %d %d %d %d", numbers, numbers+1, numbers+2, numbers+3 numbers+4);

但是,如果您不知道先验项目的数量,您可以尝试对输入进行标记,然后尝试单独转换每个项目。

char s[] = "10 22 45 67 89";

char *n = strtok(s, " ");
do { 
    numbers[k++] = atoi(n);
} while (n = strtok(NULL, " "));

请注意strtok有一个非常难看的界面 - 它会修改你传递给它的字符串,并要求你大致如上所述使用它 - 你在第一次调用中传递输入字符串,然后传递NULL为字符串标记后续调用,直到到达字符串的结尾。它在内部存储指向字符串中当前位置的指针,这也使线程安全成为问题。

您还可以sscanf使用%n转换来计算已转换的字符数,但是这些(IMO)与strtok几乎直接竞争可以想象的最丑陋的代码,我无法在一天内处理这样的事情。

答案 2 :(得分:0)

如果数字的顺序无关紧要,你可以向后循环字符串,一次一个字符。

char s[] = "10 22 45 67 89";
int i;
int tmp=0;
int mult=1;
for(i=strlen(s)-1; i>=0; i--) {
    if(s[i] != ' ') {
        tmp += (s[i]-'0') * mult;
        mult *= 10;
    } else {
        // your number is stored in tmp, do whatever you want with it
        tmp=0;
        mult=1;
    }
}

如果必须向前循环,可以使用此方法,但需要更多代码。

此方法不需要您事先知道字符串中的项目数。

答案 3 :(得分:0)

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>

typedef struct ss {//Simple stringstream mock 
    const char *p;
} Ss;

Ss *ss_new(const char *s){
    Ss *ssp = malloc(sizeof(*ssp));
    ssp->p = s;
    return ssp;
}

bool ss_nextInt(Ss *ssp, int *v){
    char *endp;
    while(isspace(*ssp->p))
        ssp->p++;
    if(!*ssp->p)
        return false;
    *v = strtol(ssp->p, &endp, 10);
    if(ssp->p != endp){
        ssp->p = endp;
        return true;
    }
    return false;
}
int main(){
    const char *s = "10 22 45 67 89";
    int numbers[100];
    int i, k=0, next_number;
    Ss *ssp =  ss_new(s);
    while(ss_nextInt(ssp, &next_number))
        numbers[k++]=next_number;
    free(ssp);
    for(i = 0; i < k; ++i)
        printf("%d\n", numbers[i]);
    return 0;
}

答案 4 :(得分:0)

<string.h>中,有许多分割字符串的选项。 strchrstrspnstrpbrk仅举几例。与用于解析数字的C90函数strtol一起,在<stdlib.h>

中定义

strpbrkstrtol

#include <stdlib.h> // strtol
#include <string.h> // strpbrk
...
const char *s = "10 22 45 67 89";
char *p = s;
int numbers[MAX_NUMBERS];
size_t i = 0;
do {
  p = strpbrk(p, "-0123456789");
  if (p == NULL) break;
  char *ptr;
  int n = (int)strtol(p, &ptr, 10);
  if (p == ptr) break; // in case *p == '-' and p[1] is not a number
  numbers[i++] = n;
} while (i < MAX_NUMBERS);

strpbrk取两个字符串并返回指向第二个字符串中提供的任何字符的第一个匹配项的指针,如果没有找到,则返回NULL

strtol接受一个字符串,一个填充指针和一个基数。它返回从第一个字符串解析的long,并使用数字末尾的位置填充指针,如果没有读取数字则填充原始字符串指针。