如何在c

时间:2015-04-26 09:05:41

标签: c

我正在使用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]);

(我使用的实际线路试图获取所有输入,但你应该看到我要去的地方......)

长期目的是将输入文件重新格式化为另一个输出文件,这样可以使眼睛更容易。

我很欣赏我可能会以错误的方式解决这个问题,但如果有人能让我走上正确的道路,我会非常感激。如果你能够在明显缺乏理解的情况下轻松对待我,我也会很感激。

感谢您阅读

3 个答案:

答案 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访问字符串时,您应该确保不超出实际的字符串长度。例如,您可以在名称后终止字符串。当您访问生日时,您访问有效的内存,但它可能包含垃圾。

您可以通过用空格填充整个字符串来避免此问题。