我正在使用C来读取外部文本文件。输入不是很好,看起来像;
0PAUL 22 ACACIA AVENUE 02/07/1986RN666
正如您所看到的,我没有明显的分隔符,有时这些值之间没有空格。但是我知道在拆分时每个值的字符长度有多长。具体如下,
id = 1
name = 20
house number = 5
street name = 40
date of birth = 10
reference = 5
我已经设置了一个我希望保存此信息的结构,并尝试使用fscanf读入该文件。 然而,我发现一些事情就是没有做我需要的事情,
fscanf(file_in, "%1d, %20s", person.id[i], person.name[i]);
(我使用的实际线路试图获取所有输入,但你应该看到我要去的地方......)
长期目的是将输入文件重新格式化为另一个输出文件,这样可以使眼睛更容易。
我很欣赏我可能会以错误的方式解决这个问题,但如果有人能让我走上正确的道路,我会非常感激。如果你能够在明显缺乏理解的情况下轻松对待我,我也会很感激。
感谢您阅读
答案 0 :(得分:2)
使用fgets一次读取每一行,然后从输入行中提取每个字段。警告:不对缓冲区执行范围检查,因此必须注意调整缓冲区的适当大小。
例如像这样的东西(我不编译它,所以可能存在一些错误):
void copy_substr(const char * pBuffer, int content_size, int start_idx, int end_idx, char * pOutBuffer)
{
end_idx = end_idx > content_size ? content_size : end_idx;
int j = 0;
for (int i = start_idx; i < end_idx; i++)
pOutBuffer[j++] = pBuffer[i];
pOutBuffer[j] = 0;
return;
}
void test_solution()
{
char buffer_char[200];
fgets(buffer_char,sizeof(buffer_char),stdin); // use your own FILE handle instead of stdin
int len = strlen(buffer_char);
char temp_buffer[100];
// Reading first field: str[0..1), so only the char 0 (len=1)
int field_size = 1;
int filed_start_ofs = 0;
copy_substr(buffer_char, len, filed_start_ofs, filed_start_ofs + field_size, temp_buffer);
}
答案 1 :(得分:2)
scanf是一种很好的方法,只需要使用缓冲区并多次调用sscanf并提供良好的偏移量。 例如:
char buffer[100];
fscanf(file_in, "%s",buffer);
sscanf(buffer, "%1d", person.id[i]);
sscanf(buffer+1, "%20s", person.name[i]);
sscanf(buffer+1+20, "%5d", person.street_number[i]);
等等。 我觉得这是最简单的方法。
还请考虑使用结构数组而不是数组结构,让person.id [i]而不是person [i] .id
感觉不对。答案 2 :(得分:1)
如果您有固定的列宽,则可以使用指针算法来访问字符串str
的子字符串。如果你有一个起始索引begin
,
printf("%s", str + begin) ;
将打印从begin
开始直到结束的子字符串。如果要打印某个length
的字符串,可以使用printf
的精度说明符.*
,它将最大长度作为附加参数:
printf("%.*s", length, str + begin) ;
如果要将字符串复制到临时缓冲区,可以使用strncpy
,如果缓冲区大于子字符串长度,则会生成空终止字符串。您也可以根据上述模式使用snprintf
:
char buf[length + 1];
snprintf(buf, sizeof(buf), "%.*s", length, str + begin) ;
这将提取前导和尾随空格,这可能不是您想要的。您可以编写一个函数来去除不需要的空格; SO上应该有很多例子。
您还可以在复制子字符串时删除空白。下面的示例代码使用isspace
中的<ctype.h>
函数/宏来执行此操作:
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
int extract(char *buf, const char *str, int len)
{
const char *end = str + len;
int tail = -1;
int i = 0;
// skip leading white space;
while (str < end && *str && isspace(*str)) str++;
// copy string
while (str < end && *str) {
if (!isspace(*str)) tail = i + 1;
buf[i++] = *str++;
}
if (tail < 0) tail= i;
buf[tail] = '\0';
return tail;
}
int main()
{
char str[][80] = {
"0PAUL 22 ACACIA AVENUE 02/07/1986RN666",
"1BOB 1 POLK ST 01/04/1988RN802",
"2ALICE 99 WEST HIGHLAND CAUSEWAY 28/06/1982RN774"
};
int i;
for (i = 0; i < 3; i++) {
char *p = str[i];
char id[2];
char name[20];
char number[6];
char street[35];
char bday[11];
char ref[11];
extract(id, p + 0, 1);
extract(name, p + 1, 19);
extract(number, p + 20, 5);
extract(street, p + 25, 34);
extract(bday, p + 59, 10);
extract(ref, p + 69, 10);
printf("<person id='%s'>\n", id);
printf(" <name>%s</name>\n", name);
printf(" <house>%s</house>\n", number);
printf(" <street>%s</street>\n", street);
printf(" <birthday>%s</birthday>\n", bday);
printf(" <reference>%s</reference>\n", ref);
printf("</person>\n\n");
}
return 0;
}
此处存在危险:当您在特定位置str + pos
访问字符串时,您应该确保不超出实际的字符串长度。例如,您可以在名称后终止字符串。当您访问生日时,您访问有效的内存,但它可能包含垃圾。
您可以通过用空格填充整个字符串来避免此问题。