在C中,我应该如何使用strtok从多项式输入中提取系数和指数?

cfh9epnr  于 2022-12-03  发布在  其他
关注(0)|答案(3)|浏览(147)

假设用户输入"-4x^0 + x^1 + 4x^3 - 4x^5 - 3x^7"作为输入,我想从字符串中提取值,并将它们传递给coef[]expo[],如下所示:

coef = [-4, 1, 0, 4, 0, -4, 0, -3]
expo = [ 0, 1, 2, 3, 4,  5, 6,  7]

这是我到目前为止所拥有的,但我不知道如何使用令牌。

int main()
{
    char userInput[100];
    char temp[100];
    printf("Enter the polynomial: ");
    scanf("%[^\n]%*c", userInput);
    strcpy(temp, userInput);
    printf("\n");
    
    int coef[100];
    int expo[100];
    for (int i = 0; i < 100; i++) {
        coef[i] = 0;
        expo[i] = 0;
    }
    
    char *tok = strtok(temp, "x^"); 
    int counter = 0;
    
    while (tok) { 
        printf("*%s*\n", tok); 
        tok = strtok(NULL, "x^"); 
        counter++; 
    } 
    
    return 0;
}

我尝试了以下方法,但没有成功:

int counter = 0;
    while (tok) { 
        printf("*%s*\n", tok);        
        expo[counter] = atoi(tok);

        tok = strtok(NULL, "x^"); 
        counter++; 
    }
zxlwwiss

zxlwwiss1#

这是一个比我最初设想的更棘手的问题,因为用户输入中存在空格,可能会丢失指数和系数--以及由于1而被省略而丢失的系数。
这是可以做到的,但是在标记化之前需要 * Decorate *,在这里,您要在指数和系数之间用新的分隔符 * 修饰 * 要标记化的字符串,以确保您可以使用strtok()。否则,由于必须保留+/-,并且输入格式可以是,例如X1 M3 N1 X,除了必须被认为是X1 M7 N1 X的一部分的X1 M6 N1 X周围的空白之外,在X1 M4 N1 X和X1 M5 N1 X之间没有定界符。
一个简单的格式化输入的临时字符串的方法是删除所有的空格,并在指数和系数之间添加一个新的'x'。这允许您使用与strtok()相同的定界符字符串,例如"x^\n",而无需调整。
对于缺失的系数和指数,可以通过从当前索引循环到指数来处理,为系数分配0,为指数分配循环计数器。然后,您可以添加当前系数和指数。
把它放在一起,并使用sscanf() * 最低限度地 * 验证每个从string到int的转换,您可以执行类似于以下的操作:

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

#define MAXC       1024   /* if you need a constant, #define one (or more) */
#define MAXCOEF     256
#define MAXEXP  MAXCOEF
#define DELIM    "x^\n"

int main (void) {
  
    char buf[MAXC], tmp[MAXC];              /* input & reformat buffers */
    int coef[MAXCOEF] = {0},                /* coefficient array */
        expo[MAXEXP] = {0},                 /* exponent array */
        n = 0, ndx = 0;                     /* counter and index */
    
    fputs ("enter polynomial: ", stdout);   /* prompt */
    
    if (!fgets (buf, MAXC, stdin)) {        /* read line in buf/validate */
      puts ("(user canceled input)");
      return 0;
    }
    
    for (int i = 0; buf[i]; i++) {          /* loop remormat buf in tmp */
      if (buf[i] != ' ') {                  /* if not space */
        if (buf[i] == '-' || buf[i] == '+') { /* if before next coef */
          tmp[n++] = 'x';                     /* decorate with new 'x' */
        }
        tmp[n++] = buf[i];                  /* add from buf to tmp */
      }
      else {  /* otherwise was ' ' */
        if (buf[i+1] == 'x') {              /* if next char is 'x' */
          tmp[n++] = '1';                   /* coef not given - use 1 */
        }
      }
    }
    tmp[n] = 0;   /* nul-terminate tmp */
    
    /* separate each token with strtok */
    for (char *tok = strtok (tmp, DELIM); tok; tok = strtok (NULL, DELIM)) {
      int ctmp, etmp;   /* temp values for coefficient and exponent */
      
      if (sscanf (tok, "%d", &ctmp) != 1) { /* convert coefficient to int */
        fprintf (stderr, "conversion failed for '%s'.\n", tok);
        return 1;
      }
      
      if (!(tok = strtok (NULL, DELIM))) {  /* get exponent token */
        break;
      }
      if (sscanf (tok, "%d", &etmp) != 1) { /* convert exponent to int */
        fprintf (stderr, "conversion failed for '%s'.\n", tok);
        return 1;
      }
      
      for (int i = ndx; i < etmp; i++) {    /* loop index to exponent */
        coef[ndx] = 0;                      /* add any missing values */
        expo[ndx++] = i;                    /* increment index */
      }
      
      coef[ndx] = ctmp;                     /* add coefficient & exponent */
      expo[ndx++] = etmp;                   /* increment index */
    }
    
    fputs ("\ncoef:", stdout);              /* output coefficients */
    for (int i = 0; i < ndx; i++) {
      printf (" % d", coef[i]);
    }
    putchar ('\n');   /* tidy up with newline */
    
    fputs ("expo:", stdout);                /* output exponents */
    for (int i = 0; i < ndx; i++) {
      printf (" % d", expo[i]);
    }
    putchar ('\n');
}

使用/输出示例

$ ./bin/strtokpoly
enter polynomial: -4x^0 + x^1 + 4x^3 - 4x^5 - 3x^7

coef: -4  1  0  4  0 -4  0 -3
expo:  0  1  2  3  4  5  6  7

它对应于您所需的输出。
把事情看一遍,如果有问题就告诉我。

nhhxz33t

nhhxz33t2#

strtok()不是解决此问题的好方法,尤其是使用"x^"作为分隔符列表,因为它将用空字节覆盖这些字符,因此无法区分2x2
另请注意,如果使用者输入的多项式长度超过99个字节,scanf("%[^\n]%*c", userInput)会有未定义的行为。应该测试scanf()的传回值,以侦测未预期的文件结尾。使用fgets()并测试传回值会比较安全。
若要解析多项式,建议一次测试一个字符,并使用strtol或类似函数转换数字。
以下是修改后的版本:

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

unsigned char skip_spaces(char *p, char **pp) {
    unsigned char c;
    while (isspace(c = *p))
        p++;
    *pp = p;
    return c;
}

void show_error(const char *error, const char *str, const char *p) {
    fprintf(stderr, "error: %s\n%s%*s^\n", error, str, (int)(p - str), "");
}

#define TERM_COUNT 100

int main() {
    char userInput[100];

    printf("Enter the polynomial: ");
    if (fgets(userInput, sizeof userInput, stdin)) {
        int coef[TERM_COUNT] = { 0 };
        int expo[TERM_COUNT] = { 0 };
        int counter;
        char *p = userInput;

        for (counter = 0; counter < TERM_COUNT; counter++) {
            int sign = 1;
            unsigned char c = skip_spaces(p, &p);
            if (c == '\0')
                break;
            if (c == '+') {
                c = skip_spaces(p + 1, &p);
            } else
            if (c == '-') {
                sign = -1;
                c = skip_spaces(p + 1, &p);
            }
            if (c == '\0') {
                show_error("missing term", userInput, p);
                break;
            }
            if (isdigit(c)) {
                coef[counter] = sign * strtol(p, &p, 10);
                c = skip_spaces(p, &p);
            } else {
                coef[counter] = sign;
            }
            if (c == 'x') {
                c = skip_spaces(p + 1, &p);
                if (c == '^') {
                    c = skip_spaces(p + 1, &p);
                    if (isdigit(c)) {
                        expo[counter] = strtol(p, &p, 10);
                        c = skip_spaces(p, &p);
                    } else {
                        show_error("missing exponent", userInput, p);
                        break;
                    }
                } else {
                    expo[counter] = 1;
                }
            } else {
                expo[counter] = 0;
            }
            if (c != '\0' && c != '+' && c != '-') {
                show_error("syntax error", userInput, p);
                break;
            }
        }
        for (int i = 0; i < counter; i++)
            printf("%+dx^%d", coef[i], expo[i]);
        printf("\n");
    }
    return 0;
}

上面的代码使用了您的方法,并用系数和指数填充了2个数组。

c9qzyr3d

c9qzyr3d3#

这对于strtok来说有点太复杂了,因为你有各种各样的隐式系数之类的极端情况。你可以走完整的解析路线,使用lex & yacc,但这可能有点矫枉过正。一种混合方法是使用fgets + sscanf来匹配特定的模式。类似于:

int main() {
    char userInput[100] = { 0 };
    printf("Enter the polynomial: ");
    fgets(userInput, sizeof(userInput), stdin);
    printf("\n");
    
    int coef[100] = { 0 };
    int expo[100] = { 0 };
    int i = 0;
    char *p = userInput;
    while (p && *p && i < 100) {
        int len;
        if (i == 0 && sscanf(p, "%d x ^%d %n", &coef[i], &expo[i], &len) == 2)) {
        } else if (sscanf(p, " +%d x ^%d %n", &coef[i], &expo[i], &len) == 2)) {
        } else if (sscanf(p, " -%d x ^%d %n", &coef[i], &expo[i], &len) == 2)) {
            coef[i] = -coef[i];
        } else if (i == 0 && sscanf(p, " x ^%d %n", &expo[i], &len) == 1) {
            coef[i] = 1;
        } else if (sscanf(p, " + x ^%d %n", &expo[i], &len) == 1) {
            coef[i] = 1;
        } else if (sscanf(p, " - x ^%d %n", &expo[i], &len) == 1) {
            coef[i] = -1;
        } else if (sscanf(p, " +%d x %n", &coeff[i], &len) == 1) {
            expo[i] = 1;
        } else if (sccanf(p, " -%d x %n", &coeff[i], &len) == 1) {
            coef[i] = -coef[i];
            expo[i] = 1;
        } else if (i == 0 && sccanf(p, "%d x %n", &coeff[i], &len) == 1) {
            expo[i] = 1;
        } else if (sscanf(p, " +%d %n", &coeff[i], &len) == 1) {
            expo[i] = 0;
        } else if (sccanf(p, " -%d %n", &coeff[i], &len) == 1) {
            coef[i] = -coef[i];
            expo[i] = 0;
        } else if (i == 0 && sccanf(p, "%d %n", &coeff[i], &len) == 1) {
            expo[i] = 0;
        } else {
            fprintf(stderr, "this doesn't look like a polynomial: %s\n", p);
            break;
        }
        p += len;
        ++i;
    }

    printf("got polynomial: ");
    for (int j = 0; j < i; ++j)
        printf("%+dx^%d", coef[j], expo[j]);
    printf("\n");
}

请注意,这可能很快变得非常复杂,需要检查许多不同的极端情况,但对于简单的事情,可能比使用完整的解析器更容易。

相关问题