0

我想在 C 中将逗号分隔的 char* 转换为 uint32_array[]。有没有简单的方法/例程可以做到这一点?

我已经在 SO 上花了很多时间,并在 C++ 上找到了许多解决方案,但不是这样的 C: Parsing a comma-delimited std::string 但我认为从 char* 转换为字符串到字符串不是一个好的解决方案流到向量并使用向量。

char input[] = "1 , 2 , 34, 12, 46, 100";

uint32_t output[] = { 1 , 2 , 34, 12, 46, 100 };

我将不胜感激任何帮助。非常感谢。

4

7 回答 7

1

一种方法(许多):

int converted = 0 ;
char* tok = input ;
int i = 0 ;
do
{
    converted = sscanf( tok, "%d", &output[i] ) ;
    tok = strchr( tok, ',' ) + 1 ;
    i++ ;

} while( tok != NULL && converted != 0 ) ;

您可以使用strtok()代替sscanf()and strchr(),但这会修改 input​​可能不受欢迎的内容。

如果输入是流而不是字符串,则更简单:

int converted = 0 ;
int i = 0 ;
do
{
    converted = fscanf( fd, "%d,", &output[i] ) ;
    i++ ;

} while( !feof( fd ) && converted != 0 ) ;

我没有包括任何防止output[i]超出范围的方法——您可能也需要考虑这一点。

于 2015-05-21T19:36:10.990 回答
1

这是一种方法:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct
{
    int* values;
    int  count;
}
output_t;

output_t Read(char input[])
{
    int*  values = NULL;
    int   count  = 0;
    char* pch    = strtok(input,", ");

    while (pch != NULL)
    {
        values = realloc(values,(count+1)*sizeof(*values));
        values[count++] = atoi(pch);
        pch = strtok(NULL,", ");
    }

    return (output_t){values,count};
}

这是一个使用示例:

void Example()
{
    char input[] = "1 , 2 , 34, 12, 46, 100";
    output_t output = Read(input);
    for (int i=0; i<output.count; i++)
        printf("%d\n",output.values[i]);
    free(output.values);
}
于 2015-05-21T19:55:14.420 回答
1

这是一个递归算法,只进行一次传递。它在最深层次分配并在出路时填写:

int *cvt(char *input, int *level)
{
    char *cp = strtok(input, ", ");
    if (cp == NULL) {
        /* No more separators */
        return (int *) malloc(sizeof(int) * *level);
    }

    int my_index = -1;
    int n;
    if (sscanf(cp, "%d", &n) == 1) {
        my_index = *level;
        *level += 1;
    } else {
        printf("Invalid integer token '%s'\n", cp);
    }
    int *array = cvt(NULL, level);
    if (my_index >= 0) {
        array[my_index] = n;
    }
    return array;
}

致电:

int main(int ac, char **av)
{
    char input[] = "1, 2, bogus, 4, 8, 22, 33, 55";
    int n_array = 0;
    int *array = cvt(input, &n_array);

    int i;
    printf("Got %d members:\n", n_array);
    for (i = 0; i < n_array; ++i)
        printf("%d ", array[i]);
    printf("\n");

    return 0;
}
于 2015-05-21T20:00:26.293 回答
1

我会把我的帽子扔进戒指并做一次数据传递。我估计所需的数组大小是最坏的情况,其中每个数据的形式为“n”,因此每个数字两个字节,然后调整它的大小。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef unsigned int uint32_t;

int main (void) {
    char input[] = "1 , 2 , 34, 12, 46, 100";
    uint32_t *output, *temp;
    char *tok;
    int elements = 0;
    int len = 1 + strlen(input) / 2;            // estimate max num of elements
    output = malloc(len * sizeof(*output));
    if (output == NULL)
        exit(-1);                               // memory alloc error

    tok = strtok(input, ", ");                  // parse the string
    while (tok != NULL) {
        if (elements >= len)
            exit(-2);                           // error in length assumption
        if (1 != sscanf(tok, "%u", output + elements))
            exit(-3);                           // error in string format
        elements++;
        tok = strtok(NULL, ", ");
    }

    temp = realloc(output, elements * sizeof(*output)); // resize the array
    if (temp == NULL)
        exit(-4);                               // error in reallocating memory
    output = temp;

    for (len=0; len<elements; len++)
        printf("%u ", output[len]);
    printf("\n");
    free(output);
    return 0;
}

程序输出:

1 2 34 12 46 100
于 2015-05-21T20:07:46.597 回答
0

通读一次字符串以了解如何调整数组的大小:

uint32_t n = 1;
for (uint32_t idx = 0; idx < strlen(input); idx++) {
    if (input[idx] == ',') {
        n++;
    }
}

有一种不同的方法可以做到这一点,不需要通读字符串,但它需要在新元素进入时调整目标数组的大小,这使得代码更加复杂。对于小字符串,一次读取字符串很容易。

制作您的目标数组:

uint32_t* output = NULL;
output = malloc(sizeof(*output) * n);
if (!output) {
    fprintf(stderr, "Error: Could not allocate space for output array!\n");
    exit(EXIT_FAILURE);
}

填充您的数组。在不破坏字符串的情况下执行此操作的一种方法是保留一对指向包含逗号分隔字符串中所需数字元素的子字符串的开头和结尾的指针,然后循环遍历字符串中的所有字符:

#define MAX_LEN 13
char* start = &input[0];
char* end = &input[0];
char entry[MAX_LEN];
uint32_t entry_idx = 0;
int finished = 0; // false
do {
    end = strchr(start, ',');
    if (!end) {
        end = input + strlen(input);
        finished = 1;
    }
    memcpy(entry, start, end - start);
    entry[end - start] = '\0';
    sscanf(entry, "%u", &output[entry_idx++]);
    start = end + 1;
} while (!finished);

MAX_LEN是 13,因为 a 不太可能uint32_t长于 13 位。对于 2100 年制造的计算机,您可以延长此时间以适应未来。

完成后一定要释放数组:

free(output); 
output = NULL;
于 2015-05-21T19:46:44.940 回答
0
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

int getsize(char* str, char* delimiters) //give the size of the final uint32_t array[]
{
  int count = 0;
  char* st = strdup(str), *t = strtok(st, delimiters);
  while(t)
  {
    count++;
    t = strtok(NULL, delimiters);
  }
  free(st);
  return count;
}

uint32_t* Char_to_Array(char *data, char* delimiters, int *siz) //siz is a pointer to get the size of the array
{
  char* st = strdup(data), *t = NULL; //dup string, strtok mage change on the passed string
  *siz = getsize(data, delimiters);
  uint32_t* buf=(uint32_t *)malloc((*siz)*4);
  t = strtok(st, delimiters); //split string by " "
  int i = 0;
  while(t)
  {
    buf[i] = atoi(t);
    t = strtok(NULL, delimiters);
    i++;
  }
  free(st);
  return buf;
}

这里有一个主要功能的测试

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

int main()
{
  int getsize(char* str, char* delimiters), siz = 0, i = 0;
  uint32_t* Char_to_Array(char *data, char* delimiters, int *x);
  uint32_t* t = Char_to_Array("123, 156, 4658,7878", " ,", &siz);
  while(i<siz)
  {
    printf("array[%d] = %d\n", i, t[i]);
    i++;
  }
  free(t);
  return 0;
}
于 2015-05-21T20:57:40.910 回答
0

2通方法:

1) 计算逗号的个数并分配一个数组。

2) 解析字符串 - 查找错误。

[迟到的 uint32 逗号派对]

#include <errno.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <inttypes.h>

typedef struct {
  uint32_t *u32;
  size_t count;
  bool error;
} CSV_32_T;

CSV_32_T CSV_to_int32_list(const char *csv) {
  CSV_32_T list = { NULL, 1, false };

  // 1st pass: Quickly go through list counting commas
  const char *p = csv;
  for (p = csv; *p; p++) {
    if (*p == ',') {
      list.count++;
    }
  }
  size_t i = 0;
  list.u32 = malloc(list.count * sizeof *list.u32);
  if (list.u32) {

    // 2nd pass: scan
    p = csv;
    for (i = 0; i < list.count; i++) {
      if (i > 0 && *p++ != ',') {
        break;
      }
      int n = 0;
      if (1 != sscanf(p, "%" SCNu32 " %n", &list.u32[i], &n)) {
        break;
      }
      p += n;
    }
  }
  if (i != list.count || *p) {
    free(list.u32);
    return (CSV_32_T ) { NULL, 0, true } ;
  }
  return list;
}

void testCSV(const char *csv) {
  CSV_32_T y = CSV_to_int32_list(csv);
  printf("%d %zu \"%s\"\n", y.error, y.count, csv);
}

int main(void) {
  testCSV("1 , 2 , 34, 12, 46, 100");
  testCSV("1  2 , 34, 12, 46, 100");
  return 0;
}
于 2015-05-21T21:33:05.590 回答