#c #parsing #arrays
#c #синтаксический анализ #массивы
Вопрос:
У меня есть такая строка: 4;4=3;1=0,2=2,3=1,4=1,5=1;0003013340f59bce000002aaf01620e620198b2240002710;
Он разделен на разделы с помощью «;», И в каждом разделе может быть одна или несколько пар ключ / значение, например 5 = 1 и так далее, как вы можете видеть. Я хочу разобрать его на чистом C, и я начал работать с strtok
тем, что я показываю в коде здесь:
const wuint8 section_delimiter[] = ";";
const wuint8 field_delimiter[] = ",";
const wuint8 value_delimiter[] = "=";
printf("%sn",data->msg);
token = strtok(data->msg,section_delimiter);
while(token != NULL) {
indicator = atoi(token);
printf("indicator: %dn", indicator);
switch(indicator) {
case TYPE_1: {
printf("type: %dn",TYPE_1);
wuint16 i, headerType, headerSubType;
for(i = 1; i < TP_MAX; i ) {
if(i == atoi(token)) {
token = strtok(NULL,value_delimiter);
headerType = i;
headerSubType = atoi(token);
break;
}
}
break;
}
case TYPE_2: {
printf("type: %dn",TYPE_3);
break;
}
case TYPE_3: {
printf("type: %dn",TYPE_3);
break;
}
case TYPE_4: {
printf("type: %dn",TYPE_4);
break;
}
Я не уверен, как это сделать правильно.
Это также усложняется, потому что не каждая строка имеет одинаковую структуру, иногда может присутствовать только один или два раздела. Например.: 3;4=3;1=0,2=2,3=1,4=1,5=1;
Есть how to
ли способ, показывающий лучший и наиболее удобный способ?
Комментарии:
1. Пожалуйста, определите «лучший» в вашем случае или удалите это предложение.
2. верно. изменен на «самый простой» 🙂
3. Я бы сказал: разделяй и властвуй. Сначала разделите строку на три раздела, разделенные символом ‘;’. затем: разберитесь с отдельными разделами, возможно, в подфункции. Подфункция также может иметь дело с пустыми сегментами.
4. Я бы пошел со strtok() Я думаю, вы сделали правильный выбор. Это не выглядит (для меня, ymmv) так, как будто вы хотите использовать что-то вроде Lex / Yacc (но, если вы это сделаете, взгляните на Antlr antlr.org Мне очень нравится графический отладчик)
Ответ №1:
strtok
AFAICR не может использоваться во вложенных циклах, подобных этому, из-за глобального состояния, которым он управляет сам. Я предлагаю сначала разобрать каждую часть, разделенную точкой с запятой, а затем обрабатывать их последовательно — или просто реализовать что-то похожее strtok
на ваш регистр с запятой самостоятельно, а затем с удовольствием использовать strtok
во внутреннем цикле.
Ответ №2:
С помощью strcspn(). Исправлены буферы, результаты переходят в глобальные переменные. буфер данных [] изменен (и, следовательно, должен быть доступен для записи). YMMV
/*
It is separated into sections by ";" and each section can have one or more
key/value pairs like 5=1 and so on, as you can see. I want to parse it in
pure C and I started working with strtok as I am showing in code here:
*/
char data[] = "4;4=3;1=0,2=2,3=1,4=1,5=1;0003013340f59bce000002aaf01620e620198b2240002710;" ;
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct header {
int l;
int r;
} headers[123];
unsigned nheader;
int indicator;
char rest [123];
int tokenise(char * buff);
unsigned tokenise2(struct header *dst, char * buff);
/****************/
int tokenise(char * buff)
{
char *ptrs[14];
unsigned nptr;
unsigned len, pos;
ptrs[nptr=0] = NULL;
for (len = pos=0; buff[pos]; pos = len ) {
len = strcspn(buff pos, ";");
ptrs[nptr ] = buff pos;
ptrs[nptr] = NULL;
if (!buff[pos len] ) break;
buff[pos len] = 0;
len =1;
}
if ( nptr> 0 amp;amp; ptrs[0]) indicator = atoi(ptrs[0]); else indicator = -1;
if ( nptr> 1 amp;amp; ptrs[1]) nheader = tokenise2 (headers, ptrs[1] ); else nheader = 0;
if ( nptr> 2 amp;amp; ptrs[2]) nheader = tokenise2 (headers nheader, ptrs[2] ); else nheader = 0;
if ( nptr> 3 amp;amp; ptrs[3]) strcpy (rest, ptrs[3]); else rest[0] = 0;
return 0; /* or something useful ... */
}
unsigned tokenise2(struct header *target, char * buff)
{
char *ptrs[123];
unsigned nptr, iptr;
unsigned len, pos;
ptrs[nptr=0] = NULL;
for (len = pos=0; buff[pos]; pos = len ) {
len = strcspn(buff pos, "," );
ptrs[nptr ] = buff pos;
ptrs[nptr] = NULL;
if (!buff[pos len] ) break;
buff[pos len] = 0;
len =1;
}
for ( iptr=0; iptr < nptr; iptr ) {
if (! ptrs[iptr] ) break;
len = strcspn(ptrs[iptr], "=" );
if (!len) break;
target[iptr].l = atoi (ptrs[iptr] );
target[iptr].r = atoi (ptrs[iptr] len 1 );
}
return iptr; /* something useful ... */
}
int main(void)
{
int rc;
unsigned idx;
fprintf(stderr, "Org=[%s]n", data );
rc = tokenise(data);
printf("Indicator=%dn", indicator );
for (idx=0; idx < nheader; idx ) {
printf("%u: %d=%dn", idx, headers[idx].l , headers[idx].r );
}
printf("Rest=%sn", rest );
return 0;
}