简体   繁体   English

将字符串拆分为3d数组

[英]splitting a string into a 3d array

let's say that we have a string str : 假设我们有一个字符串str

String str = "1,2,3,4444444444;5,6,7,8888888888;.9,10,11,1212121212;.";

defining three dimensions d1 , d2 and d3 that are embedded in the string as follow: 定义嵌入在字符串中的三个维d1d2d3 ,如下所示:

  • d1 has elements that are separated by a dot "." d1元素由点“。”分隔。
  • d2 has elements that are separated by a semicolon ";" d2元素由分号“;”分隔
  • d3 has elements that are separated by a comma "," d3元素以逗号“,”分隔

d3 is a child of d2 and d2 is a child of d1 (parent). d3是一个孩子d2d2是一个孩子d1 (父)。 d1 > d2 > d3 . d1 > d2 > d3

we wish to have access to every element embedded in the string, meaning that we should have -as a result- an array as follows: 我们希望可以访问字符串中嵌入的每个元素,这意味着我们应具有-结果是一个如下数组:

d[0][0][0] = "1";
d[0][0][1] = "2";
d[0][0][2] = "3";
d[0][0][3] = "4444444444";
d[0][1][0] = "5";
d[0][1][1] = "6";
d[0][1][2] = "7";
d[0][1][3] = "8888888888";
d[1][0][0] = "9";
d[1][0][1] = "10";
d[1][0][2] = "11";
d[1][0][3] = "12121212";
  • you can see that d[i][j][k] where k = [0, 2] are integers. 您会看到d[i][j][k] ,其中k = [0, 2]是整数。
  • you can see that d[i][j][k] where k = 3 are long integers. 您会看到d[i][j][k] ,其中k = 3是长整数。

we wish to convert these strings to their appropriate integer type now (either a regular integer or a long integer). 我们希望现在将这些字符串转换为适当的整数类型(常规整数或长整数)。 meaning that our final array should look like this: 表示我们的最终数组应如下所示:

d[0][0][0] = 1; // int
d[0][0][1] = 2; // int
d[0][0][2] = 3; // int
d[0][0][3] = 4444444444; // long int
d[0][1][0] = 5; // int
d[0][1][1] = 6; // int
d[0][1][2] = 7; // int
d[0][1][3] = 8888888888; // long int
d[1][0][0] = 9; // int
d[1][0][1] = 10; // int
d[1][0][2] = 11; // int
d[1][0][3] = 12121212; // long int

this idea is to be implemented on an arduino microcontroller, which is c/c++ based. 这个想法将在基于c / c ++的arduino微控制器上实现。

here is my take on it, not working properly unfortunately. 这是我的看法,不幸的是无法正常工作。

  String data = "1,2,3,1445303228;4,5,6,1445303228;.7,8,9,1445303273;.";

  int data_length = data.length() + 1;

  if (data_length != 1) {

    char d0[data_length]; // couldn't do it with String, let's try char
    data.toCharArray(d0, data_length);

    int size1 = 32, size2 = 64; // intuitive sizes

    char d1[size1][136]; // strlen("1,2,3,1445303228") * 8, 17 * 8 = 136

    int i = 0;
    for (char *p = strtok(d0, "."); p != NULL; p = strtok(NULL, "."))
    strcpy(d1[i++], p); // d1

    int d1_length = i;

    char d2[d1_length][size2][17]; // strlen("1,2,3,1445303228") = 16

    int d2_length[size2];
    for (int i = 0; i < size2; i++) d2_length[i] = 0; // initialize array = 0

    for (int i = 0; i < d1_length; i++) {
      int j = 0;
      for (char *p = strtok(d1[i], ";"); p != NULL; p = strtok(NULL, ";"))
      strcpy(d2[i][j++], p); // d2

      d2_length[i] = j;
    }

    int d2_length_max = 0;
    for (int i = 0; i < size2; i++)
    if (d2_length[i] > d2_length_max) d2_length_max = d2_length[i];

    char d3[d1_length][d2_length_max][4][10];
    // d2 can have 4 d3's max, d3 can have 10 chars max

    for (int i = 0; i < d1_length; i++) {
      for (int j = 0; j < d2_length[i]; j++) {
        int k = 0;
        for (char *p = strtok(d2[i][j], ","); p != NULL; p = strtok(NULL, ","))
        strcpy(d3[i][j][k++], p); // d3
      }
    }

    int rows[d1_length][d2_length_max][3];
    long rows_long[d1_length][d2_length_max];

    for (int i = 0; i < d1_length; i++)
    for (int j = 0; j < d2_length[i]; j++)
    for (int k = 0; k < 3; k++)
    rows[i][j][k] = atoi(d3[i][j][k]); // char array to integer

    for (int i = 0; i < d1_length; i++)
    for (int j = 0; j < d2_length[i]; j++) {
      char temp[10];
      for (int k = 0; k < 10; k++) temp[k] = d3[i][j][3][k];
      rows_long[i][j] = atol(temp); // char array to long
    }

  }

please note that the long integer is infact a unix timestamp. 请注意,长整数实际上是unix时间戳。

With a dynamic flat array in pure C and then alloc the 3D array The array size is double each time needed You can set the first size with the define: 使用纯C中的动态平面数组,然后分配3D数组。每次需要时,数组大小都会加倍。您可以使用define设置第一个大小:

#define DEFAULT_SIZE 8 

as said in my comment the format is strange ;. 如我的评论所述,格式很奇怪;. should be . 应该是. and the final ;. 和最后;. should be removed 应该删除

I add test to check if next line as the same size than the first one. 我添加测试以检查下一行是否与第一行相同。

int main(void) { 
    char *data = "1,2,3,1445303228;4,5,6,1445303228;.7,8,9,1445303273;."; 
    char *p; 
    int size = DEFAULT_SIZE; 
    int nb_element = 0; 
    int s1 = 0; 
    int s2 = 0; 

    int cur1 = 0; 
    int cur2 = 0; 
    int cur3 = 0; 

    int *d = malloc(sizeof(int) * DEFAULT_SIZE); 
    int ***d3; 

    if (!d) { 
        return -1; 
    } 

    p = data; 
    while (*p) { 
        if (nb_element == size) { 
            size *= 2; 
            d = realloc(d, size * sizeof(int)); 
            if (!d) { 
                return -1; 
            } 
        } 
        d[nb_element++] = strtol(p, &p, 10); 
        switch (*p) { 
          case ',': 
            cur1++; 
            if (s1 && cur1 > s1) { 
                fprintf(stderr, "Too many element for %d, %d:" 
                        " get %d, expect %d\n", cur2, cur3, cur1, s1); 
                return -1; 
            } 
            break; 
          case ';': 
            cur1++; 
            cur2++; 
            if (s1 == 0) { 
                s1 = cur1; 
            } 
            cur1 = 0; 
            if (s2 && cur2 > s2) { 
                fprintf(stderr, "Too many element for %d:" 
                        " get %d, expect %d\n", cur3, cur2, s2); 
                return -1; 
            } 
            break; 
          case '.': 
          dot: 
            cur2++; 
            cur3++; 
            if (s2 == 0) { 
                s2 = cur2; 
            } 
            cur2 = 0; 
            cur1 = 0; 
            break; 
        } 
        p++; 
        /* XXX: ack due to strange format */ 
        if (*p == '.') 
            goto dot; 
    } 
    /*XXX! remove empty final line */ 
    cur3--; 

    d3 = malloc(sizeof(int **) * cur3); 
    for (int i = 0; i < cur3; i++) { 
        d3[i] = malloc(sizeof(int *) * s2); 
        for (int j = 0; j < s2; j++) { 
            d3[i][j] = malloc(sizeof(int) * s1); 
            for (int k = 0; k < s1; k++) {  
                d3[i][j][k] = d[i * s2 + j * s1 + k]; 
            } 
        } 
    } 
    free(d); 
    for (int i = 0; i < cur3; i++) { 
        for (int j = 0; j < s2; j++) { 
            for (int k = 0; k < s1; k++) { 
                fprintf(stdout, "d[%d][%d][%d] = %d\n", i,j,k, d3[i][j][k]); 
            } 
        } 
    } 
    return 0; 
} 

output: 输出:

d[0][0][0] = 1
d[0][0][1] = 2
d[0][0][2] = 3
d[0][0][3] = 1445303228
d[0][1][0] = 4
d[0][1][1] = 5
d[0][1][2] = 6
d[0][1][3] = 1445303228
d[0][2][0] = 7
d[0][2][1] = 8
d[0][2][2] = 9
d[0][2][3] = 1445303273
#include <stdio.h>
#include <stdlib.h>

int c1,c2,c3;

int n=0;
char sResult[20];

void PrintLevel(int lvl){
    if(n){
        printf("d[%d][%d][%d] = \"%s\"\n",c3,c2,c1,sResult);
        n=0;
    }
    switch(lvl){
        case 3:
            c3++;
            c2=c1=0;
            break;
        case 2:
            c2++;
            c1=0;
            break;
        case 1:
            c1++;
    }

    return ;
}

void addChar(char c){
    sResult[n]=c;
    n++;
    sResult[n]=c=0;
}
/*______________________________________________________________________
*/

int main(){
    char buff[]= "0,1,2,4444444444;5,6,7,8888888888;.9,10,11,12121212;.";
    PrintLevel(0);
    char *p=buff;
    char c;
    int ret;
    int lvl;
    while(c=*p){

        lvl=(c==',')?1:((c==';')?2:((c=='.')?3:0) );

        if(lvl)
            PrintLevel(lvl);
        else
            addChar(c);
        p++;
    }
    PrintLevel(lvl);

}

First note that a long is too small to hold even: 4444444444 It's max size is: 2147483647 首先请注意, long太小而无法容纳: 4444444444 它的最大大小是: 2147483647

If a long long is used however the string can be eloquently parsed by a regex_token_iterator . 如果使用了long long那么可以通过regex_token_iterator雄辩地解析该字符串。 The parsing function should take in the input string and the delimiter and return separated strings . 解析函数应接受输入string和定界符,并返回分隔的strings These inputs enable reuse in a function similar to this one: 这些输入可实现类似于以下功能的重用:

auto parse(const string& input, const string& delimiter) {
    const regex re("([^" + delimiter + "]+)" + delimiter + '?');

    return vector<string>(sregex_token_iterator(input.begin(), input.end(), re, 1), sregex_token_iterator());
}

This will return the input in a partitioned vector<string> . 这将以分区vector<string>返回input This return can then be partitioned until the third dimension in which each partition will contain only numeric characters. 然后可以对返回值进行分区,直到每个分区只包含数字字符的第三维。 At that point stoll can be used to convert the string to a long long . 到那时, stoll可用于将string转换为long long This partitioning can be accomplished in nested loops like this: 可以在嵌套循环中完成此分区,如下所示:

vector<vector<vector<long long>>> foo;

for (auto& i : parse(str, "\\.")) {
    foo.resize(foo.size() + 1);
    for (auto& j : parse(i, ";")) {
        foo.back().resize(foo.back().size() + 1);
        for (auto& k : parse(j, ",")) {
            foo.back().back().push_back(stoll(k));
        }
    }
}

One key aspect of this is that each partition must contain a number. 一个关键方面是每个分区必须包含一个数字。 This is enforced by the '+' in re which will not match if consecutive delimiters occur. 这是由执行'+'re如果连续的分隔符发生的不匹配。 stoll is very robust and will eat whitespace if that is in the input string , however if a string containing only whitespace or generally does not contain a number is fed to it it will throw an error. stoll非常健壮,并且如果在输入string包含空格,它将吃掉空格;但是,如果将仅包含空格或通常不包含数字的string输入给它,则会引发错误。 If that is a concern be sure to check your inputs before calling stoll . 如果这是一个问题,请确保在致电stoll之前检查您的输入。

You can see a live example of this here: http://ideone.com/4vjdBx 您可以在此处看到一个实时的示例: http : //ideone.com/4vjdBx

got it working with a code that is mainly based on @milevyo's answer . 使用主要基于@milevyo的答案的代码来实现它。

struct ds { int a = 0, b = 0, c = 0; long d = 0; };

struct data {
  struct ds array[32][8];
  int i, j[24];

  int n = 0, d1, d2, d3; char r[11];
  void get(String array) {
    if (array.length() + 1 != 1) {
      char buff[array.length() + 1];
      array.toCharArray(buff, array.length() + 1);
      char c; char *p = buff; int l;
      while (c = *p) {
        l = (c == ',') ? 1 : ((c == ';') ? 2 : ((c == '.') ? 3 : 0));
        if (l) a(l); else ch(c); p++;
      }
      a(l);
    }
  }
  void a(int l) {
    if (n) {
      if (d1 == 0) array[d3][d2].a = atoi(r);
      else if (d1 == 1) array[d3][d2].b = atoi(r);
      else if (d1 == 2) array[d3][d2].c = atoi(r);
      else if (d1 == 3) array[d3][d2].d = atol(r);
      i = d3 + 1; j[d3] = d2 + 1; n = 0;
    }
    switch (l) {
      case 3: d3++; d2 = d1 = 0; break;
      case 2: d2++; d1 = 0; break;
      case 1: d1++; break;
    }
  }
  void ch(char c) { r[n] = c; n++; r[n] = c = 0; }
} data;

void setup () {
  Serial.begin(19200); 
  Serial.println(".."); 

  data.get("1,2,3,1445433855;4,5,6,1445433855;.7,8,9,1445438763;.");

  for (int i = 0; i < data.i; i++) {
    for (int j = 0; j < data.j[i]; j++) {
      for (int k = 0; k < 4; k++) {
        if (k == 0) Serial.print(data.array[i][j].a);
        else if (k == 1) Serial.print(data.array[i][j].b);
        else if (k == 2) Serial.print(data.array[i][j].c);
        else if (k == 3) Serial.print(data.array[i][j].d);
        Serial.print("\t");
      }
      Serial.println();
    }
    Serial.println();
  }
}

void loop () { }

from

1,2,3,1445433855;4,5,6,1445433855;.7,8,9,1445438763;.

to

..
1   2   3   1445433855  
4   5   6   1445433855  

7   8   9   1445438763  

via 通过

..
data.array[0][0].a  data.array[0][0].b  data.array[0][0].c  data.array[0][0].d
data.array[0][1].a  data.array[0][1].b  data.array[0][1].c  data.array[0][1].d

data.array[1][0].a  data.array[1][0].b  data.array[1][0].c  data.array[1][0].d

i hope you saved the last post, this is an update to the last one, it handle 2D arrays as requested. 我希望您保存了上一篇文章,这是对上一篇文章的更新,它可以按要求处理2D数组。 hope you find it useful, if so send me a postcard :) 希望您觉得有用,如果是,请给我寄明信片:)

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


/*__________________________________________________________________________
*/

struct DATA{
   char a;
   char b;
   char c;
   unsigned long d;
};


/*__________________________________________________________________________

  allocate DATA struct, and fill it.
  on error or no data, returns NULL
*/
struct DATA *ParseString(char **pstr){
    int val=0;
    char *p;
    struct DATA *data;
    if(!pstr) return NULL;

    char *str=*pstr;
    if(!str) return NULL;

    // can be ommited
    // skipping non digital chars
    while(*str && !isdigit(*str))
        str++;

    //no digits?
    if(!*str) return NULL;

    p=str;
    //ok at least one
    data=(struct DATA*) calloc(1,sizeof(struct DATA));//calloc to initialize all to 0
    for(int n=0;n<4;n++){
        val=0;
        while(isdigit(*p)){
            val*=10;
            val+=(*p)-'0';
            p++;
        }
        switch(n){
            case 0:
                data->a=val;
                break;
            case 1:
                data->b=val;
                break;
            case 2:
                data->c=val;
                break;
            case 3:
                data->d=val;
                break;
        }
        val=0;
        if(*p!=',')
            break;
        p++;

    }
    *pstr=p;
    return data;
}
/*__________________________________________________________________________

    calculate the size of DATA * arra[c1][c2]
*/
void countArrBoudaries(char *s,unsigned short *c1,unsigned short *c2){
    *c1=*c2=0;
    unsigned short _c1=0;
    while(*s){
        switch(*s){
            case ';':
                _c1++;
                break;
            case '.':
                if(_c1>*c1)
                    *c1=_c1;
                _c1=0;
                *c2+=1;
                break;
        }
        s++;
    }
}
/*__________________________________________________________________________
*/
int main(void){

    struct DATA **pdata,*data;
    char buff[]="1,2,3,1445303228;4,5,6,1445303228;.7,8,9,1445303273;.";
    char *p=buff;
    unsigned short c1,c2;
    countArrBoudaries(buff,&c1,&c2);
    pdata=(struct DATA**)calloc((c2*c1),sizeof(pdata));

    if(pdata){
        // loading
        for(int i=0;i<c1;i++)
            for(int j=0;j<c2;j++)
                pdata[i+(j*c1)]=ParseString(&p);

        // printing:
        for(int i=0;i<c1;i++)
            for(int j=0;j<c2;j++){
                data=pdata[i+(j*c1)];
                if(data){
                    printf("data[%u][%u]={%d,%d,%d,%u};\n",i,j,data->a,data->b,data->c,data->d);
                }else{
                    printf("data[%u][%u]=NULL;\n",i,j);
                }
            }

        // freeing memory:
        for(int i=0;i<(c1*c2);i++)
            free(pdata[i]);
        free(pdata);

    }
    printf("\n\nDONE\n\n");
    return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM