如何使用fscanf()输入不同的参数?

时间:2013-07-20 03:30:44

标签: c++ c

我尝试使用fscanf()从txt文件输入参数。 这是我的代码:

fpin = fopen("parameter_file.txt","r");
fscanf(fpin,"%d\n", &code_value);
fscanf(fpin,"%d\n", &origin_x);
fscanf(fpin,"%d\n", &origin_y);
fscanf(fpin,"%d\n", &dpi);
fscanf(fpin,"%d\n", &width);
fscanf(fpin,"%d\n", &height);

并且parameter_file.txt是(例如):

333 
123 
123 
800
6
8

我想在每一行之后添加一些注释。例如: 333 //code_value123 //origin_x我的问题是,当我添加一些字符时,fscanf()无法正常工作,因为我希望读取连续参数。

我试过了fscanf(fpin,"%[^a-z]%d\n", &code_value);

另一个问题是输入文件如下,我的代码怎么实现?

333 //code_value_1
123 //origin_x_1
123 //origin_y_1
800 //dpi_1
6 //width_1
8 //height_1
12 // code_value_2
10 //origin_x_2
20 //origin_y_2
800 //dpi_2
10 //width_2
10 //height_2
.
.
.
20 // code_value_n
10 //origin_x_n
20 //origin_y_n
800 //dpi_n
30 //width_n
30 //height_n

1 个答案:

答案 0 :(得分:5)

如果格式总是每行一个数字,您可以使用:

fscanf(fpin, "%d%*[^\n]", &var);

%*[^\n]将吞下所有字符直到换行符。 *是抑制,^\n表示除换行符之外的所有字符都是扫描集的一部分。

但是,如果新行紧跟在该号码后面,则旧样式输入将失败。更健壮的方法是首先将整行读入缓冲区,然后使用sscanf()strtol()解析缓冲区。

char buf[MAX_LINE_LENGTH];

if (fgets(buf, sizeof(buf), fpin) != 0) {
    if (sscanf(buf, "%d", &var) == 1) {
        /* ... */
    } else {
        /* ...handle parse error */
    }
} else {
    /* ...handle file read error */
}

在C ++中,可以使用getline()istringstream进行类似的操作。

std::string line;
std::istringstream iss;

if (std::getline(std::cin, line)) {
    iss.str(line);
    if (iss >> var) {
        //...
    } else {
        //...handle scan error
    }
} else {
    //...handle read error
}

在评论中,您会问:

  

如何将每个cin分配给不同的参数?

如果每个注释都描述了值所代表的含义,则可以使用map<string, int>创建名称与值的关联。由于注释不遵循常规格式,因此解析时必须变得棘手。

C版本使用数组来存储关联。然后,您可以在以后对其进行排序(使用qsort()),并在需要查找时使用bsearch())对其执行二进制搜索。

struct value_item {
    char name[MAX_NAME_SIZE];
    int value;
};

struct value_item value_map[MAX_VALUE_MAP];
size_t value_map_size = 0;

while (fgets(buf, sizeof(buf), fpin) != 0) {
    const char *slash2 = strstr(buf, "//");
    if (slash2 && slash2[2] != '\0') {
        sscanf(buf, "%d", &value_map[value_map_size].value);
        sscanf(slash2+2, "%s", value_map[value_map_size].name);
        ++value_map_size;
    } else {
        /* ...handle parse error */
    }
}

C ++版本看起来很相似。 C ++提供map,您可以使用它来轻松创建关联。

std::map<std::string, int> value_map;

while (std::getline(std::cin, line)) {
    std::string::size_type n = line.find("//");
    if (n != std::string::npos && line.size() > (n+2)) {
        int value;
        std::string name;
        iss.str(line);
        iss >> value;
        iss.str(line.substr(n+2));
        iss >> name;
        value_map[name] = value;
    } else {
        //...handle parse error
    }
 }

我正在写这篇文章,所以可能会有错误,以及更好的方法。但是,这应该给你一般的想法。