我有一个输入。txt文件,看起来像这样:
Robert Hill 53000 5
Amanda Trapp 89000 3
Jonathan Nguyen 93000 3
Mary Lou Gilley 17000 1 // Note that came contains of 3 parts!
Warren Rexroad 72000 7
我需要读取这些行并将它们解析为三个不同的类别:名称(这是一个字符数组),里程(int)和年份(int)。
sscanf(line, "%[^] %d %d ", name, &mileage, &years);
这对我来说不是很好,有什么建议吗?
问题
传递给sscanf
的当前说明符的问题是,它是病态的,即使修复了它也不会做您想要的。如果您使用[^ ]
作为第一个转换说明符, sscanf
将尝试在击中空格之前读取尽可能多的字符。
如果我们假设名称不能包含数字,则指定[^0123456789]
将读取正确的数据,但它还将包括名称之后,但在第一个里程条目之前的尾随空格。然而,这很容易通过将name
中的最后一个空格替换为空字节来解决。
为了得到读进name
的字符数,我们可以使用%n
说明符来指示sscanf
存储读进匹配实参的字节数;稍后我们可以使用这个值来正确地"trim"我们的缓冲区。
我们还应该指定%[^0123456789]
读取的字符的最大宽度,这样它就不会导致缓冲区溢出,这是通过直接在%
之后指定缓冲区的大小来完成的。
<
示例实现/strong>
#include <stdio.h>
#include <string.h>
int
main (int argc, char *argv[])
{
char const * line = "Mary Lou Gilley 17000 1";
char name[255];
int mileage, years, name_length;
sscanf(line, "%254[^0123456789]%n %d %d ", name, &name_length, &mileage, &years);
name[name_length-1] = ' ';
printf ("data: '%s', %d, %d", name, mileage, years);
return 0;
}
<一口> 一口>
data: 'Mary Lou Gilley', 17000, 1
如果你有一个查找第一个数字位置的函数,如下所示:
// This function returns the position of the
// space before the first digit (assuming that
// the names dont contain digits)...
char *digitPos(char *s){
if isdigit(*(s+1)) return s;
else return digitPos(s+1);
}
您可以通过在正确位置插入' '
来分隔两个变量,如下所示:
pos = digitPos(line); // This is a pointer to the space
*pos = ' ';
strcpy(name, line);
sscanf(pos + 1, "%d %d", &mileage, &years);
这可能会帮助您开始。它缺乏BLUEPIXY解决方案的智能,它处理尾随空格的能力比我的好一点(或者你可以自己把它切掉)。
dan@rachel ~ $ echogcc -o t t.c
dan@rachel ~ $ echo "Dan P F 3 21" | ./t
Name: Dan P F ,
Mileage: 3,
Years: 21.
代码如下:
#include <stdio.h>
#include <string.h>
int main(){
char *buf;
int mileage, years;
while(!feof(stdin) ){
if( fscanf( stdin, "%m[^0-9] %d %d", &buf, &mileage, &years) == 3 ){
fprintf(stderr, "Name:t %s,nMileage:t %d,nYears:t %d.n",
buf, mileage, years
);
}
}
}
您已经发现了永远不应该使用*scanf
的三个原因之一:编写处理重要输入语法的格式规范几乎是不可能的,特别是当您不得不担心从格式错误的输入中恢复时。但还有两个更重要的原因:
- 许多输入规范,包括你的
%[...]
结构,就像臭名昭著的gets
一样乐于溢出缓冲区。 - 数字溢出会引发未定义的行为——C库允许崩溃,仅仅因为有人输入了太多数字。
正确的解析这些行的方法是使用strcspn("0123456789", line)
或while (*p && !isdigit(*p)) p++;
扫描第一个数字,然后使用strtoul
转换后面的数字。
int pos;
sscanf(line, "%*[^0-9]%n", &pos);
line[--pos]=';';
sscanf(line, "%[^;]; %d %d ", name, &mileage, &years);
相关内容
- 没有找到相关文章
最新更新
- R函数转换为HTML
- 裸机中的 Kubernetes 证书管理器问题:等待 HTTP-01 质询传播:状态代码"403"错误,预期'200'
- 使用钩子将状态从一个组件传递到另一个组件(不是子组件)
- 当我们使用暂存标志(--暂存)进行"npm build"时,如何在应用程序中创建"NON PRODUCTION"横幅?
- 循环访问列表,为每个项目创建新列表,然后将新列表作为参数传递给函数,但"var referenced before assignment"
- React单元测试Jest使用Typescript mount()的问题
- 是否有一种方法来隐藏代码使用Swift包管理器?
- 如何限制游戏循环fps?
- Django将更复杂的python类型传递给模板
- r语言 - 创建可使用元素访问的响应值列表
- ECharts Apache:条形图-添加水平水平线
- aws Cloudfront的维护页面
- 是否有任何方法为我的php应用程序从计算机到整个互联网?
- 根据指定值计算集合中所有可能的值组合
- 如何将Django模型限制为单个一对一关系?
- 尽管有"max-size"命令,但 docker-compose 未轮换失控的 docker 日志
- 使用元组作为索引来比较列表中的项
- 如何修复"javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting wit
- c -使用中断或线程和全局变量进行优化
- Html语言中带有fetch方法的Onclick回调
- 如何调试SQL Server 2018中的存储过程
- 如何修复我的代码从serial1接收数据并按下一个值并将其发送到serial0,同时运行步进电机 &
- CentOS安装R包RLumShiny失败
- 解析字符串以创建几何图形
- restorePreviousSignIn()在GIDSignIn-iOS SDK V6.0.2到期时不获取新的idTo
- 从Nodejs发送的错误请求-原始消息缺少头部信息
- Oracle 将今天的值传递给变量并使用它
- r语言 - 是否有可能把3D网格和arc3d对象在同一个rgl窗口,同时允许单独旋转?
- 依次递增的号码,如123 + 123 = 123123
- SQL:如何使用参数变量重命名标题?
热门标签:
javascript python java c# php android html jquery c++ css ios sql mysql arrays asp.net json python-3.x ruby-on-rails .net sql-server django objective-c excel regex ruby linux ajax iphone xml vba spring asp.net-mvc database wordpress string postgresql wpf windows xcode bash git oracle list vb.net multithreading eclipse algorithm macos powershell visual-studio image forms numpy scala function api selenium