分别扫描 C 中的句子和数字
Separately scanning a sentence and number(s) in C
假设我有一个文本文件 (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 "eats up"整行。我也不能使用 %s,因为名称的字数不同。所以,我想知道是否有办法将扫描分开......或者有没有更好的方法来解决这个问题......
谢谢。
尝试
fscanf(fr,"%99[^0-9]%lf%lf ", name, &h, &w)!=EOF)
这会吃掉行首的名字,然后是数字,然后是新行。
您必须 trim 删除名称末尾的空格。 How do I trim leading/trailing whitespace in a standard way? 应该能帮到你
解决该问题的另一种标准方法是简单地使用设置到行尾的指针,然后备份——修剪空格(和 null 终止)直到找到字母或数字——然后就可以了备份直到找到下一个空格。由于您的指针现在指向 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;
}
示例Use/Output
$ ./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 > buf && (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
使用显式检查空格代替 isspace()
,等等。您可以使用 strpbrk
在字符串中向前扫描您的第一个数字,并从那里向前和向后工作.不管你怎么做,关键是把你的字符串写在一张纸上,然后用铅笔前后移动你的指针位置,同时找出你需要的测试和索引。
检查一下,如果您还有其他问题,请告诉我。
假设我有一个文本文件 (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 "eats up"整行。我也不能使用 %s,因为名称的字数不同。所以,我想知道是否有办法将扫描分开......或者有没有更好的方法来解决这个问题......
谢谢。
尝试
fscanf(fr,"%99[^0-9]%lf%lf ", name, &h, &w)!=EOF)
这会吃掉行首的名字,然后是数字,然后是新行。
您必须 trim 删除名称末尾的空格。 How do I trim leading/trailing whitespace in a standard way? 应该能帮到你
解决该问题的另一种标准方法是简单地使用设置到行尾的指针,然后备份——修剪空格(和 null 终止)直到找到字母或数字——然后就可以了备份直到找到下一个空格。由于您的指针现在指向 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;
}
示例Use/Output
$ ./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 > buf && (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
使用显式检查空格代替 isspace()
,等等。您可以使用 strpbrk
在字符串中向前扫描您的第一个数字,并从那里向前和向后工作.不管你怎么做,关键是把你的字符串写在一张纸上,然后用铅笔前后移动你的指针位置,同时找出你需要的测试和索引。
检查一下,如果您还有其他问题,请告诉我。