【问题标题】:Separately scanning a sentence and number(s) in C分别扫描C中的句子和数字
【发布时间】:2018-05-02 19:04:02
【问题描述】:

假设我有一个文本文件 (hw.dat),其中列出了数据(姓名、身高(cm)、体重(kg)):

Yuri            164     80 
Lai San Young   155     60
John Wayne      180     93

列表还在继续。

我想以这种格式扫描和打印所有数据:

name: Yuri, height: 164, weight: 80
name: Lai San Young, height: 155, weight: 60

等等。

这是我失败的尝试(代码段)。我打算编写代码,在逐行打印数据的同时逐行读取 hw.dat 文件:

double h, w;
char name[100];

FILE *fr;
fr = fopen ("hw.dat", "r");

while (fscanf(fr,"%[^\n]s %lf %lf", name, &h, &w)!=EOF)
{
    printf ("name: %s, height: %lf, weight: %lf \n", name, h, w);
}

fclose (fr);

%[^\n]s “吃掉”了整行。我也不能使用 %s 因为名字的单词数不同。所以,我想知道是否有任何方法可以分开扫描......或者有没有更好的方法来解决这个问题......

谢谢。

【问题讨论】:

  • 阅读整行,然后找到最后两个空格(将名称与数字分开的空格,并将两个数字分开)。提取这两个数字并解析它们,然后你就得到了名字(可能还有一些你可以修剪的尾随空格)。
  • 使用fgets并自己解析字符串。
  • %[^\n]*c %lf %lf?

标签: c file-io scanf eof line-by-line


【解决方案1】:

试试

fscanf(fr,"%99[^0-9]%lf%lf ", name, &h, &w)!=EOF)

这将吃掉行首的名称,然后是数字,然后是新行。

您必须修剪名称以删除末尾的空格。 How do I trim leading/trailing whitespace in a standard way? 应该能帮到你

【讨论】:

  • 我应该把!=EOF -> ==3
【解决方案2】:

解决该问题的另一种标准方法是简单地使用设置为行尾的指针,然后备份——修剪空格(和 nul 终止)直到找到一个字母或数字——然后只是备份直到你找到下一个空格。由于您的指针现在指向 weight 之前的最后一个空白,只需保存指向 current + 1 的指针,它将指向 weight 的开头(再次重复 height

您现在保存了指向height 的指针,并且您的指针现在指向height 之前的最后一个空格。只需继续备份空格(nul-terminating),直到您到达下一个字母或数字(这将是名称的结尾)或者您点击字符串的开头(发生了一些事情错了,你没有找到`姓名,身高,体重)。

由于您一直nul-terminating到那时,您知道您现在读取的缓冲区仅包含name,因此您可以简单地打印输出并阅读下一行。绝对没有什么是你不能简单地通过将一个指针(或一对指针)沿着一个字符串(或者在这种情况下是一个字符串)移动来解析的

总而言之,您可以执行类似于以下的操作:

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

enum { MAXHW = 2, MAXC = 512 };  /* if you need constants, define them */

int main (int argc, char **argv) {

    char buf[MAXC] = "";    /* line buffer */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    while (fgets (buf, MAXC, fp)) { /* read each line */
        char *p = buf,              /* pointer to buf */
             *hw[MAXHW] = {NULL};   /* array of MAXHW pointers */
        int ndx = 0;                /* array index */

        while (*p) p++;             /* find end of buf */
        p--;                        /* backup to last char */

        while (p > buf) {   /* while pointer within buf */
            /* loop checking if char is a trailing space, tab, newline, ... */
            while (p > buf && isspace (*p))
                *p-- = 0;   /* overwrite with nul-terminating char */
            /* loop checking each char is a letter or digit */
            while (p > buf && isalnum (*p))
                p--;        /* just backup to previous char */
            hw[ndx++] = p + 1;  /* space before word found, save ptr to word */
            if (p != buf)   /* if not at beginning */
                *p = 0;     /* nul-terminate */
            else
                break;          /* at beginning - bail */
            if (ndx == MAXHW)   /* if both h & w filled */
                break;          /* bail */
            p--;    /* backup to previous and keep going */
        }
        if (p > buf && ndx == MAXHW) { /* not at beginning & H & W found */
            p--;    /* backup to previous */
            /* trim trailing whitespace to end of name */
            while (p > buf && isspace (*p))
                *p-- = 0;
        }
        /* output results */
        printf ("name: %s, height: %s, weight: %s\n", buf, hw[1], hw[0]);
    }
    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    return 0;
}

使用/输出示例

$ ./bin/readhw <dat/hw.dat
name: Yuri, height: 164, weight: 80
name: Lai San Young, height: 155, weight: 60
name: John Wayne, height: 180, weight: 93

有很多很多不同的方法可以做到这一点。您可能没有使用 ctype.h 并检查过,例如if (p &gt; buf &amp;&amp; (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') 使用对空白的显式检查代替isspace() 等。您可以使用strpbrk 在字符串中向前扫描您的第一个数字,并从那里向前和向后工作。不管你怎么做,关键是把你的字符串写在一张纸上,然后用铅笔前后移动你的指针位置,同时找出你需要的测试和索引。

如果您有其他问题,请查看并告诉我。

【讨论】:

    猜你喜欢
    • 2011-02-18
    • 2013-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-03
    • 2016-02-13
    • 1970-01-01
    • 2013-10-09
    相关资源
    最近更新 更多