2017-11-28 11 views
1

私は記号とその値の文字列に関する問題があります。私は文字列の各部分のデータを取得し、独自のバッファに保存したいと思います。 は、たとえば、この文字列から:文字列から数値を抽出し、それを独自のバッファに保存する方法は?

char str = "+TY123-UP65.4-FA545-MTE565-MTD65-MTT230-MPE545-MPD656-MPT345-"; 

私は、各記号はその場所を取った後に文字を比較したいです。最初は新しい文字列を示す "+"記号です。次に、 " - "記号が現れる(セクションの終わりを示す)前に、それぞれの最初の2つか3つの値を比較したい。例えば、TYの前にあるTYなら、 "TYbuffer"に続く数値(intまたはfloat) " - "記号まで。その後、 " - "チェックの後、どの文字が最初であるかを確認し、 "UP"であれば "UPbuffer"などに保存します。

まず、私はこのような文字列を経る:

size_t len = strlen(str); 
size_t i; 
for (i=0;i<len;i++){ //go through the string 
int j=0; 
    if (str[j] == '+' && str[j+1]=='T'){ //Check for the letters 
    } 
} 

これは私がそれを行うだろうかの例であるが、問題は、位置がずれることができるように、数字が大きくても小さくてもできるということです。私は問題を解決するのにちょっと混乱しています。私は文字列から数字を抽出しようとしましたが、その人はそれがどの特定のセクションから来たのかわかりません。このように:

char tmp[20]; 
void loop() { 
char *str = "+TY123-UP65.4-FA545-MTE565-MTD65-MTT230-MPE545-MPD656-MPT345-"; 
char *p = str; 
while (*p) { 
     if (str == 'T'){ 
     while (*p) { 
      if (isdigit(*p)) { // Upon finding a digit 
      long val = strtol(p, &p, 10); // Read a number 
      sprintf(tmp, "%1d", val); 
      Serial.println(val); // and print it 
      } else { 
      p++; 
      } 
     } 

参考までに、私はArduinoプラットフォームを使用しています。

文字列からint/float値を抽出することができましたが、これは私が注意しなければならないエラーのビットです。私は最初に "+"記号を取り除いた。ここで、さらにコードは次のとおりです。

#include <stdlib.h> 

void setup() { 
    Serial.begin(9600); 
    char str[] = "TY123-UP65.4-FA545-MTE565-MTD65-MTT230-MPE545-MPD656-MPT345-"; 
    Serial.write(str); 
    analyzeString(str); 
} 

void loop() { 

} 

void analyzeString(char* str) { 

    int count = 0;         //start the count 
    char buff[20];         //initialiye the buffer for 20 char 

    for(int i = 0; i<strlen(str); i++) {   //start the loop for reading the characters from whole string 
     if(str[i] == '-') {       //start the loop when "-" occurs 
     char bufNum[20];       //buffer for the number in a seperate section 
     //char bufNum1[20]; 
     if (buff[0] == 'T' && buff[1] == 'Y') { //If the first letter in a buffer is U and second is P 
      for(int j = 2; j<count; j++) {   
      bufNum[j-2] = buff[j]; 
      } 
      bufNum[count-2] = '\0'; 
      Serial.println(); 
      int ty = atoi(bufNum);     //atof(string) for float, atoi(string) for int 
      Serial.print(ty);      //float constant 

     } else if (buff[0] == 'U' && buff[1] == 'P'){ 
      for(int j = 2; j<count; j++) { 
      bufNum[j-2] = buff[j]; 
      } 
      bufNum[count-2] = '\0'; 
      Serial.println(bufNum); 
      float up = atof(bufNum); 
      Serial.print(up); 
     } else if (buff[0] == 'F' && buff[1] == 'A'){ 
      for(int j = 2; j<count; j++) { 
      bufNum[j-2] = buff[j]; 
      } 
      bufNum[count-2] = '\0'; 
      Serial.println(bufNum); 
      int fa = atoi(bufNum); 
      Serial.print(fa); 
     } 


     count =0; 

     } else { 
      buff[count++] = str[i]; 
     } 
    } 
} 

それは、このようなセクションの次の値を出力しているため、エラーが出力である:

TY123-UP65.4-FA545-MTE565-MTD65-MTT230-MPE545-MPD656-MPT345- 
12365.4 
65.40545 
545 

私はアプローチすべきかのガイドを探しています問題。助けていただければ幸いです。ありがとうございました。

+3

文字列をトークン化する必要があります。 – mnistic

+0

'Serial.println(val);':これはCですか? arduino? –

+2

mnisticが正しい場合、指定した文字(この場合は ' - ')の文字列をトークン化するためにループ内でstrtok()を使用してみてください。これは ' - '文字を取り除き、実際に見たいデータへのポインタを与えます。 –

答えて

3

文字列から、あなたのセクションを解析し、各セクションからラベルと値を解析アプローチするいくつかの方法があります。何よりもまず、文字列の下にポインタを置いて、適切な処置をとって、'+', '-', 'letter', 'digit'をチェックするだけで何も問題はありません。

しかし、Cはまた、セクション解析を自動化することができるstrtokstrtodの便利なツールをいくつか提供しています。double(またはをstrtodの代わりにstrtofの代わりに使用)の数値を格納し、小数部が存在する場合にのみ出力する%gの出力を処理することもできます。古いC89コンパイラ(例えばWin7の/ VS 10)にコンパイルする場合はC89は提供しなかったとして、あなたはsection sect[MAXSECT] = {{0},0};を初期化することができ:

#include <stdio.h> 
#include <stdlib.h>  /* for strtod */ 
#include <string.h>  /* for strlen */ 
#include <ctype.h>  /* for isalpha */ 
#include <errno.h>  /* for errno */ 

#define MAXSECT 16  /* if you need a constant, define one */ 

typedef struct {  /* struct to hold label & value */ 
    char str[MAXSECT]; 
    double d; 
} section; 

int main (void) { 

    int n = 0;    /* number of sections */ 
    char buf[] = "+TY123-UP65.4-FA545-MTE565-MTD65-MTT230-MPE545-MPD656-MPT345-", 
     *p = buf,   /* pointer to buf */ 
     *delim = "+-";  /* delimiters for strtok */ 
    section sect[MAXSECT] = {{ .str = "" }}; /* array of MAXSECT sections */ 

    /* tokenize buf splitting on '+' and '-' */ 
    for (p = strtok(p, delim); p; p = strtok (NULL, delim)) { 
     size_t len = strlen (p), idx = 0; /* length and label index */ 
     char *ep = p;  /* 'endptr' for strtod */ 

     if (len + 1 > MAXSECT) { /* check length of section fits */ 
      fprintf (stderr, "error: section too long '%zu' chars '%s'.\n", 
        len, p); 
      continue; 
     } 

     while (isalpha (*p)) /* while letters, copy to sect[n].str */ 
      sect[n].str[idx++] = *p++; 
     sect[n].str[idx++] = 0; /* nul-terminate sect[n].str */ 

     errno = 0; 
     sect[n].d = strtod (p, &ep); /* convert value, store as double */ 
     if (p != ep)     /* validate digits converted */ 
      if (errno) {    /* validate no error on converstion */ 
       perror ("conversion to number failed"); 
       continue; 
      } 
     if (++n == MAXSECT) {   /* increment n, check if array full */ 
      fprintf (stderr, "sect array full.\n"); 
      break; 
     } 
    } 

    for (int i = 0; i < n; i++) /* output results, fraction only if present */ 
     printf ("buf[%3s] : %g\n", sect[i].str, sect[i].d); 

    return 0; 
} 

注:

フォックスたとえば、あなたは次のように何かを行うことができます名前の初期化子のために。また、上部にn付き)

使用例/出力

でカウンタ変数iを宣言する必要があります。
$ ./bin/strtok_str_sect 
buf[ TY] : 123 
buf[ UP] : 65.4 
buf[ FA] : 545 
buf[MTE] : 565 
buf[MTD] : 65 
buf[MTT] : 230 
buf[MPE] : 545 
buf[MPD] : 656 
buf[MPT] : 345 

すべての回答を見てみると、良い学習があります。さらに質問がある場合はお知らせください。

+0

素晴らしい、答えてくれてありがとう。私はそれを走らせることができた。 – Drejc

0

私はそれが少し圧倒的な解決策だと思うし、あなたにアイデアを与えるためにかなり速く書いた。

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

struct data { 
    char id[20]; 
    int i_value; 
    float f_value; 
}; 


static int get_ar_size(const char *str) 
{ 
    int count = 0; 

    while (*str != '\0') { 
     if (*str == '+' || *str == '-') 
      count++; 
     *str++; 
    } 
    return (count); 
} 

static int is_float_string(const char **tmp) 
{ 
    int is_float = 1; 
    int is_int = 0; 
    for(; *(*tmp) != '\0' && *(*tmp) != '+' && *(*tmp) != '-'; *(*tmp)++) { 
     if (*(*tmp) == '.') 
      return (is_float); 
    } 

    return (is_int); 
} 

static void get_info_from_string(const char *str, int i, 
           struct data strct_arr[]) 
{ 
    int j = 0; 
    const char *tmp = NULL; 

    /*write two letter ID into id array*/ 
    while (*str != '\0' && *str != '-' && *str != '+' && isalpha(*str)) { 
      strct_arr[i].id[j++] = *str++; 
    } 

    tmp = str; 
    /* then write value for that letter ID */ 
    while (*tmp != '\0' && *tmp != '-' && *tmp != '+' && isdigit(*tmp)) { 
     /* check it is float or it is integer */ 
     if(is_float_string(&tmp)) { 
      strct_arr[i].f_value = atof(&(*str)); 
      break; 
     } 
     else { 
      strct_arr[i].i_value = atoi(&(*str)); 
      break; 
     } 
     *tmp++; 
    } 
} 


int main(void) 
{ 
    const char *str = "+TY123-UP65.4-FA545-MTE565-MTD65-MTT230-MPE545-MPD656-MPT345-"; 
    int size = 0; 
    int index = 0; 

    /*count every '+' and '-' it would be our size for struct array*/ 
    size = get_ar_size(str); 

    /* create array of structure which has first letter buf id and its value */ 
    struct data *strct_arr = malloc(sizeof(struct data) * size + 1); 
    if (strct_arr == NULL) { 
     perror("Malloc failed: "); 
     return EXIT_FAILURE; 
    } 

    bzero(strct_arr, sizeof(strct_arr)); 
    for (index = 0; *str != '\0'; *str++) { 
     if ((*str == '+' || *str == '-') && (isalpha(*(str+1)))) { 
      *str++; 
      get_info_from_string(&(*str), index, strct_arr); 
      index++; 
     } 
    } 

    index = 0; 
    while(index < size) { 
     if (strct_arr[index].i_value == 0) { 
      printf("ID [%s] float %.1f\n", strct_arr[index].id, strct_arr[index].f_value); 
     } 
     else 
      printf("ID [%s] int %d\n", strct_arr[index].id, strct_arr[iindex].i_value); 
     index++; 
    } 
return 0; 
} 

エラーチェックはほとんどありませんので、ご注意ください。ちょうどあなたがそれから書き直すことができると思う。文字列から取る出力:

"+TY123-UP65.4-FA545-MTE565-MTD65-MTT230-MPE545-MPD656-MPT345-"; 

ID [TY] int 123 
ID [UP] float 65.4 
ID [FA] int 545 
ID [MTE] int 565 
ID [MTD] int 65 
ID [MTT] int 230 
ID [MPE] int 545 
ID [MPD] int 656 
ID [MPT] int 345 
+0

お元気でありがとう、ありがとう。私はこのソリューションをさらに開発することを検討します。私はコードの編集もアップロードしました。それを確認してください:) – Drejc

0

strtokを使用する方法です。私はstrtokがArduinoで利用できないと考えていますが、代わりにstrtok_rを使用することができます。

int main() 
{ 
    char str[] = "+TY123-UP65.4-FA545-MTE565-MTD65-MTT230-MPE545-MPD656-MPT345-"; 
    //char *context; 
    //char *token = strtok_r(str, "+-", &context); 
    char *token = strtok(str, "+-"); 
    while(token) 
    { 
     for(size_t i = 0, len = strlen(token); i < len; i++) 
     { 
      if(!isdigit(token[i])) continue; 

      //text part, example TY 
      char str_name[10]; 
      strncpy(str_name, token, i); 
      str_name[i] = 0; 

      //integer part, example 123 
      char *temp = token + i; 

      if(strstr(temp, ".")) 
       printf("%s %.2f\n", str_name, strtof(temp, &temp)); 
      else 
       printf("%s %d\n", str_name, strtol(temp, &temp, 10)); 

      break; 
     } 
     //token = strtok_r(NULL, "+-", &context); 
     token = strtok(NULL, "+-"); 
    } 
    return 0; 
} 

Run on ideone

+0

投稿していただきありがとうございます。私は間違いなくあなたが投稿したものを検討します。私はまたちょっと違った方法でコードを編集しました。それをチェックしてください:) – Drejc

0

あなたが構築しているものはレクサーです。この質問には、いくつかの良い情報があります。lexers vs parsers

これにアプローチする方法の1つは、いくつかのトークンタイプを定義することです。各タイプには、照合する文字のセットと、許可された後続のタイプのリストがあります。これはデータ構造でもハードコードでも構いませんが、あなたの思考をクリアするためにそれを書き出すべきです。

  1. 有効な最初のタイプが何であるかは予期しません。
  2. キャラクターをつかむ
  3. 有効なタイプのリストを調べることで、どのようなトークンタイプになるかを解説します。そのタイプの新しいトークンを開始します。
  4. 他のキャラクターをつかむ。
  5. 文字が現在のトークンに収まる場合は、文字列に追加します。これは元の文字列のコピーでも構いませんし、シンボルの開始位置と文字数を指すポインタを持つこともできます。 4から繰り返す。
  6. 適合しない場合、トークンを出力する。その出力は、戻り値、 "out"パラメータ、関数コールバック、またはリストや配列のようなデータ構造に追加することができます。 2から繰り返します。または、呼び出し元に戻った場合は、もう一度呼び出されるのを待ちます。
  7. 最終的にデータが不足したり、エラーが発生して終了します。

各トークンはそれ自身のデータ構造体である。トークンが見つかった位置とトークンの種類を含める必要があります。もちろん、トークン列。

トークンの種類は、[+ - ]の後に[A-Z]、その後に[0-9。]、先頭に[+ - ]が続きます。

手順4と5をstrspnの機能で置き換えることができます。

この後、トークンを受け取るコードは、混在している各文字を読み取るための低レベルの詳細を持たないため、より簡単な時間が必要です。

関連する問題