我正在尝试创建一个算法来读取具有这种形状的文件:
+6.590472E-01;+2.771043E+07;+
-5.003500E-02;-8.679890E-02;-
如您所见,它有三列。其中两个是数字,最后一个是信号。
我已将该行作为char [30]并且列以分号分隔。
现在,让我们假设数字为" + 6.590472E-01"。我需要将它分成四个信息:符号(+
或-
),点前的数字(0到9,在这种情况下为6),点和指数之间的数字( 590472)最后是指数(-01)。
如何使用fscanf
检索这些信息?我必须使用哪种模式?
答案 0 :(得分:2)
假设声明如下:
char s1[2], s2[2], s3[2];
char int1[21], int2[21], frac1[21], frac2[21];
char exp1[6], exp2[6];
并假设您使用fgets()
或
getline()
成为字符串变量string
,然后您可以使用sscanf()
一次性解析字符串,如下所示:
if (sscanf(string, "%1[-+]%20[0-9].%20[0-9]%*[eE]%5[-+0-9];%1[-+]%20[0-9].%20[0-9]%*[eE]%5[-+0-9];%1[-+]",
s1, int1, frac1, exp1, s2, int2, frac2, exp2, s3) != 9)
…something went wrong — at least we can analyze the string…
else
…got the information…
请注意在格式字符串中使用20
,但在变量声明中使用21
;这个一个接一个是很久以前(大约1979年)在标准I / O库中做出的设计决定,远在标准之前。 %*[eE]
允许e
或E
作为指数标记,并禁止分配。请注意,指数项将允许E9-8+7
作为指数,并且不会坚持使用符号;除非你分两部分收集指数,否则没有一个简单的方法。
您也不能简单地告诉扫描完成的位置。您可以在最后添加%n
转换规范,并将&n
作为额外参数传递(使用int n;
作为变量定义)。 %n
未计算在内,因此条件不变。然后,您可以检查buffer[n]
以查看转换停止的位置 - 是换行符还是字符串结尾,还是虚假的东西?
请注意,因为格式字符串始终使用%[…]
个扫描集,所以不会消耗任何空格 - 输入中的任何空格都会触发错误。
这需要对sscanf()
的规范有相当全面的了解。在接下来的一个月左右你可能需要阅读它六次才能开始掌握它,然后在明年重新读它六次,之后你可能会得到它离开年度修订版 - 它是一个复杂的函数(scanf()
函数族是标准C中最复杂的函数。)
#include <stdio.h>
int main(void)
{
char string[] = "+6.590472E-01;+2.771043E+07;+\n";
char s1[2], s2[2], s3[2];
char int1[21], int2[21], frac1[21], frac2[21], exp1[6], exp2[6];
int n;
int rc;
if ((rc = sscanf(string, "%1[-+]%20[0-9].%20[0-9]%*[eE]%5[-+0-9];%1[-+]%20[0-9].%20[0-9]%*[eE]%5[-+0-9];%1[-+]%n",
s1, int1, frac1, exp1, s2, int2, frac2, exp2, s3, &n)) == 9)
{
printf("[%s][%s].[%s]E[%s]\n", s1, int1, frac1, exp1);
printf("[%s][%s].[%s]E[%s]\n", s2, int2, frac2, exp2);
printf("[%s] %d (%d = '%c')\n", s3, n, string[n], string[n]);
}
else
printf("Oops (rc = %d)!\n", rc);
return 0;
}
输出:
[+][6].[590472]E[-01]
[+][2].[771043]E[+07]
[+] 29 (10 = '
')
正如chqrlie中comment所述,编写if
语句的更好方法可能更像:
if ((rc = sscanf(string, "%1[-+]%20[0-9].%20[0-9]%*[eE]%5[-+0-9];"
"%1[-+]%20[0-9].%20[0-9]%*[eE]%5[-+0-9];" "%1[-+]%n",
s1, int1, frac1, exp1,
s2, int2, frac2, exp2, s3, &n)) == 9)
这使用相邻的字符串连接来强调格式字符串的前两个段是相同的,然后或多或少地分割变量以匹配。有许多类似的布局也可以使用。
答案 1 :(得分:0)
如果您确定他们有这种格式,您只需使用:
int z = sscanf(var,"%g;%g;%c,&float1,&float2,&char1);
其中char1
是一个char
,而float1
和float2
是float
。
验证z == 3
以确保您已成功填充三个变量。
编辑:我看到你想要分开的部分;然后你可以使用:
int z = sscanf(var,"%c%d.%[^E]E%3c;%c%d.%[^E]E%3c;%c",...)
具有适当数量的变量。 %c
将第一个符号读入char,%d
整数,点被丢弃,%[^E]
读直到&#39; E&#39 ;然后是&#39; E&#39;被丢弃,%3c
读取指数,依此类推。
这些格式也适用于fscanf - 无论如何fscanf内部映射到scanf。