3

我尝试使用 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_value或者123 //origin_x我的问题是当我添加一些字符时, fscanf() 无法正常工作,因为我希望读取 continue 参数。

我努力了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
4

1 回答 1

5

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

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

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

但是,如果换行符紧跟在数字后面,这将在您的旧样式输入中失败。更健壮的方法是先将整行读入缓冲区,然后使用sscanf()or解析缓冲区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 分配给不同的参数?

如果每个注释都描述了值所代表的内容,则可以使用 amap<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
    }
 }

我是在脑海中写下这个,所以可能会有错误,还有更好的方法来做到这一点。但是,这应该给你一个大致的想法。

于 2013-07-20T03:39:22.470 回答