我对一串标志及其价值有疑问。我想获取每个字符串的数据并将其保存到自己的缓冲区中。 例如,从这个字符串:
char str = "+TY123-UP65.4-FA545-MTE565-MTD65-MTT230-MPE545-MPD656-MPT345-";
我希望在每个符号取代之后比较字符。首先是“+”符号,表示新的数据字符串。然后我想在“ - ”符号出现之前比较每个前两个或三个值(它表示部分的结尾),如果是,例如,在数字之前的TY保存数字(int或float)跟随“TYbuffer” “直到” - “的标志。然后在“ - ”之后再次检查哪些字母是第一个,如果是“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
我正在寻找一个如何处理问题的指南。我将不胜感激任何帮助。谢谢。
答案 0 :(得分:3)
有许多方法可以从字符串中解析部分,然后解析每个部分的标签和值。首先,简单地沿着字符串向下走指针,检查'+', '-', 'letter', 'digit'
然后采取适当的行动绝对没有错。
但是,C还在strtok
和strtod
中提供了一些方便的工具,可以自动执行部分解析,并为您的数字转换验证其中的一些单调乏味。您也可以选择将数值存储为double
(或float
使用strtof
而不是strtod
),然后使用%g
来处理输出输出小数部分(如果存在)。
Fox的例子,你可以做类似的事情:
#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;
}
(注意:如果在旧的C89编译器(例如Win7 / VS 10)上进行编译,则可以初始化section sect[MAXSECT] = {{0},0};
,因为C89没有提供命名的初始值设定项。您还需要在顶部声明计数器变量i
以及n
)
示例使用/输出
$ ./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
查看所有答案,总体上有很好的学习方法。如果您还有其他问题,请与我们联系。
答案 1 :(得分: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
答案 2 :(得分:0)
这是一种使用strtok
的方法。我认为在Arduino中无法使用strtok
,您可以使用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;
}
答案 3 :(得分:0)
在我看来,你正在建造的是一个词法分析器。您可以在这个问题上找到一些好的信息:lexers vs parsers
解决此问题的一种方法是定义一些令牌类型。每种类型都有一组要匹配的字符和一组允许的后续类型。这可以是数据结构或硬编码,但你应该写出来清除你的想法。
每个令牌都是自己的数据结构。它应该包括找到令牌的位置以及令牌所在的东西的类型。当然还有令牌字符串。
您的令牌类型看起来像[+ - ]后跟[A-Z]后跟[0-9。],然后回到开头,然后是[+ - ]。
您可以使用strspn
功能替换步骤4和5。
在此之后,接收令牌的代码应该更容易,因为它不会有读取每个字符的低级细节。