Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/webpack/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么从std::istream读取记录结构字段失败,我如何修复它?_C++_Parsing_C++11_Iostream - Fatal编程技术网

C++ 为什么从std::istream读取记录结构字段失败,我如何修复它?

C++ 为什么从std::istream读取记录结构字段失败,我如何修复它?,c++,parsing,c++11,iostream,C++,Parsing,C++11,Iostream,假设我们有以下情况: 记录结构声明如下 struct Person { unsigned int id; std::string name; uint8_t age; // ... }; #include <iostream> #include <vector> struct Person { unsigned int id; std::string name; uint8_t age; // ...

假设我们有以下情况:

  • 记录结构声明如下

    struct Person {
        unsigned int id;
        std::string name;
        uint8_t age;
        // ...
    };
    
    #include <iostream>
    #include <vector>
    
    struct Person {
        unsigned int id;
        std::string name;
        uint8_t age;
        // ...
    };
    
    int main() {
        std::istream& ifs = std::cin; // Open file alternatively
        std::vector<Person> persons;
    
        Person actRecord;
        unsigned int age;
        while(ifs >> actRecord.id >> age && 
              std::getline(ifs, actRecord.name)) {
            actRecord.age = uint8_t(age);
            persons.push_back(actRecord);
        }
    
        return 0;
    }
    
  • 记录以以下格式存储在文件中:

    ID名Lastname年龄
    ------------------------------
    1267867约翰·史密斯32
    67545无名氏36
    8677453格温妮丝·米勒56
    75543 J.罗斯23
    ...
    
应读入该文件以收集任意数量的上述
个人
记录:

std::istream& ifs = std::ifstream("SampleInput.txt");
std::vector<Person> persons;

Person actRecord;
while(ifs >> actRecord.id >> actRecord.name >> actRecord.age) {
    persons.push_back(actRecord);
}

if(!ifs) {
    std::err << "Input format error!" << std::endl;
} 

名字和姓氏之间有空格。将您的类更改为将firstname和lastname作为单独的字符串,它应该可以工作。您可以做的另一件事是读入两个单独的变量,例如
name1
name2
,并将其指定为

actRecord.name = name1 + " " + name2;
一种是对输入字段重新排序(如果可能的话)

并按如下方式阅读记录

struct Person {
    unsigned int id;
    std::string name;
    uint8_t age;
    // ...
};
#include <iostream>
#include <vector>

struct Person {
    unsigned int id;
    std::string name;
    uint8_t age;
    // ...
};

int main() {
    std::istream& ifs = std::cin; // Open file alternatively
    std::vector<Person> persons;

    Person actRecord;
    unsigned int age;
    while(ifs >> actRecord.id >> age && 
          std::getline(ifs, actRecord.name)) {
        actRecord.age = uint8_t(age);
        persons.push_back(actRecord);
    }

    return 0;
}
#包括
#包括
结构人{
无符号整数id;
std::字符串名;
8岁;
// ...
};
int main(){
std::istream&ifs=std::cin;//交替打开文件
性病媒人;
个人记录;
无符号整数;
而(ifs>>actRecord.id>>年龄和
std::getline(ifs,actRecord.name)){
actRecord.age=uint8_t(年龄);
人员。推回(actRecord);
}
返回0;
}

解决方案是在
ID
变量的第一个条目中读取。
然后读入该行中的所有其他单词(只需将它们放入临时向量中),并用所有元素构建个体的名称,最后一个条目是年龄

这将允许你在最后一个职位上仍然有年龄,但能够处理像“J.Ross不同寻常”这样的名字

更新以添加一些说明上述理论的代码:

#include <memory>
#include <string>
#include <vector>
#include <iterator>
#include <fstream>
#include <sstream>
#include <iostream>

struct Person {
    unsigned int id;
    std::string name;
    int age;
};

int main()
{
    std::fstream ifs("in.txt");
    std::vector<Person> persons;

    std::string line;
    while (std::getline(ifs, line))
    {
        std::istringstream iss(line);

        // first: ID simply read it
        Person actRecord;
        iss >> actRecord.id;

        // next iteration: read in everything
        std::string temp;
        std::vector<std::string> tempvect;
        while(iss >> temp) {
            tempvect.push_back(temp);
        }

        // then: the name, let's join the vector in a way to not to get a trailing space
        // also taking care of people who do not have two names ...
        int LAST = 2;
        if(tempvect.size() < 2) // only the name and age are in there
        {
            LAST = 1;
        }
        std::ostringstream oss;
        std::copy(tempvect.begin(), tempvect.end() - LAST,
            std::ostream_iterator<std::string>(oss, " "));
        // the last element
        oss << *(tempvect.end() - LAST);
        actRecord.name = oss.str();

        // and the age
        actRecord.age = std::stoi( *(tempvect.end() - 1) );
        persons.push_back(actRecord);
    }

    for(std::vector<Person>::const_iterator it = persons.begin(); it != persons.end(); it++)
    {
        std::cout << it->id << ":" << it->name << ":" << it->age << std::endl;
    }
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
结构人{
无符号整数id;
std::字符串名;
智力年龄;
};
int main()
{
std::fstream ifs(“in.txt”);
性病媒人;
std::字符串行;
while(std::getline(ifs,line))
{
标准::istringstream iss(线);
//第一:我只是读了一下
个人记录;
iss>>actRecord.id;
//下一次迭代:阅读所有内容
std::字符串温度;
std::向量tempvect;
而(iss>>温度){
临时向后推(临时);
}
//然后:名称,让我们以不获得尾随空格的方式连接向量
//还要照顾那些没有两个名字的人。。。
int LAST=2;
if(tempvect.size()<2)//其中只包含姓名和年龄
{
LAST=1;
}
std::ostringstream oss;
std::copy(tempvect.begin(),tempvect.end()-LAST,
std::ostream_迭代器(oss,“”);
//最后一个要素
开放源码软件
如何将构成名称的单独单词读入一个
actRecord.name
变量

一般的答案是:,如果没有额外的分隔符规范和对构成预期的
actRecord.name
内容的部分的异常解析,您就无法做到这一点。
这是因为将解析
std::string
字段,直到下一次出现空白字符

值得注意的是一些标准格式(如
.csv
)可能需要支持区分空格(
'
)与制表符(
'\t'
)或其他字符,以界定某些记录字段(乍一看可能不可见)

另请注意:

要将
uint8\u t
值作为数字输入读取,必须使用临时的
无符号int
值进行偏差。只读取
无符号字符(又称
uint8\u t
)将破坏流解析状态。

以下是我提出的一个操纵器的实现,该操纵器通过每个提取的字符对分隔符进行计数。使用您指定的分隔符数量,它将从输入流中提取单词。这是一个工作演示

模板
结构字插入器{
word\u inserter\u impl(std::size\u t words,std::basic\u string&str,图表delim)
:str(str)
,德利姆(德利姆)
,字(字)
{ }
friend std::basic_istream&
操作员>>(标准::基本\u istream&is、常量字\u插入器\u impl&wi){
typename std::basic_istream::sentry ok(is);
如果(确定){
istreambuf_迭代器it(is),end;
std::back\u insert\u迭代器dest(wi.str\u);
while(it!=end&&wi.words){
if(*it==wi.delim&&--wi.words==0){
打破
}
dest++=*it++;
}
}
回报是;
}
私人:
标准::基本字符串和str;
查特·德里姆;
可变标准::大小\u t单词\u;
};
模板
word\u inserter\u impl word\u inserter(std::size\u t words,std::basic\u string&str,charT delim=charT(“”)){
返回单词\u inserter\u impl(单词、str、delim);
}
现在,您只需执行以下操作:

while(ifs>>actRecord.id>>word\u插入器(2,actRecord.name)>>actRecord.age){

std::cout另一种解决方案是要求特定字段使用某些分隔符,并为此提供一个特殊的提取操纵器

假设我们定义了分隔符
,输入应该如下所示:

1267867 "John Smith"      32   
67545   "Jane Doe"        36  
8677453 "Gwyneth Miller"  56  
75543   "J. Ross Unusual" 23  
一般需要包括:

#include <iostream>
#include <vector>
#include <iomanip>
代理类(结构)的声明/定义,该类支持与
std::istream&operator>>(std::istream&,const delim\u field\u extractor\u proxy&)一起使用。
全局运算符重载:

struct delim_field_extractor_proxy { 
    delim_field_extractor_proxy
       ( std::string& field_ref
       , char delim = '"'
       ) 
    : field_ref_(field_ref), delim_(delim) {}

    friend 
    std::istream& operator>>
       ( std::istream& is
       , const delim_field_extractor_proxy& extractor_proxy);

    void extract_value(std::istream& is) const {
        field_ref_.clear();
        char input;
        bool addChars = false;
        while(is) {
            is.get(input);
            if(is.eof()) {
                break;
            }
            if(input == delim_) {
                addChars = !addChars;
                if(!addChars) {
                    break;
                }
                else {
                    continue;
                }
            }
            if(addChars) {
                field_ref_ += input;
            }
        }
        // consume whitespaces
        while(std::isspace(is.peek())) {
            is.get();
        }
    }
    std::string& field_ref_;
    char delim_;
};

将所有连接在一起的内容进行管道连接,并实例化delim\u字段\u提取器\u代理

int main() {
    std::istream& ifs = std::cin; // Open file alternatively
    std::vector<Person> persons;

    Person actRecord;
    int act_age;
    while(ifs >> actRecord.id 
              >> delim_field_extractor_proxy(actRecord.name,'"')
              >> act_age) {
        actRecord.age = uint8_t(act_age);
        persons.push_back(actRecord);
    }

    for(auto it = persons.begin();
        it != persons.end();
        ++it) {
        std::cout << it->id << ", " 
                      << it->name << ", " 
                      << int(it->age) << std::endl;
    }
    return 0;
}
intmain(){
std::istream&ifs=std::
std::istream& operator>>
    ( std::istream& is
    , const delim_field_extractor_proxy& extractor_proxy) {
    extractor_proxy.extract_value(is);
    return is;
}
int main() {
    std::istream& ifs = std::cin; // Open file alternatively
    std::vector<Person> persons;

    Person actRecord;
    int act_age;
    while(ifs >> actRecord.id 
              >> delim_field_extractor_proxy(actRecord.name,'"')
              >> act_age) {
        actRecord.age = uint8_t(act_age);
        persons.push_back(actRecord);
    }

    for(auto it = persons.begin();
        it != persons.end();
        ++it) {
        std::cout << it->id << ", " 
                      << it->name << ", " 
                      << int(it->age) << std::endl;
    }
    return 0;
}
#include <iostream>
#include <fstream>
#include <deque>
#include <vector>
#include <sstream>
#include <iterator>
#include <string>
#include <algorithm>
#include <utility>

struct Person {
    unsigned int id;
    std::string name;
    uint8_t age;
};
int main(int argc, char* argv[]) {

    std::ifstream ifs("SampleInput.txt");
    std::vector<Person> records;

    std::string line;
    while (std::getline(ifs,line)) {

        std::istringstream ss(line);

        std::deque<std::string> info(std::istream_iterator<std::string>(ss), {});

        Person record;
        record.id = std::stoi(info.front()); info.pop_front();
        record.age = std::stoi(info.back()); info.pop_back();

        std::ostringstream name;
        std::copy
            ( info.begin()
            , info.end()
            , std::ostream_iterator<std::string>(name," "));
        record.name = name.str(); record.name.pop_back();

        records.push_back(std::move(record));
    }

    for (auto& record : records) {
        std::cout << record.id << " " << record.name << " " 
                  << static_cast<unsigned int>(record.age) << std::endl;
    }

    return 0;
}
int main()
{
   std::ifstream ifs("test-115.in");
   std::vector<Person> persons;

   while (true)
   {
      Person actRecord;
      // Read the ID and the first part of the name.
      if ( !(ifs >> actRecord.id >> actRecord.name ) )
      {
         break;
      }

      // Read the rest of the line.
      std::string line;
      std::getline(ifs,line);

      // Pickup the rest of the name from the rest of the line.
      // The last token in the rest of the line is the age.
      // All other tokens are part of the name.
      // The tokens can be separated by ' ' or '\t'.
      size_t pos = 0;
      size_t iter1 = 0;
      size_t iter2 = 0;
      while ( (iter1 = line.find(' ', pos)) != std::string::npos ||
              (iter2 = line.find('\t', pos)) != std::string::npos )
      {
         size_t iter = (iter1 != std::string::npos) ? iter1 : iter2;
         actRecord.name += line.substr(pos, (iter - pos + 1));
         pos = iter + 1;

         // Skip multiple whitespace characters.
         while ( isspace(line[pos]) )
         {
            ++pos;
         }
      }

      // Trim the last whitespace from the name.
      actRecord.name.erase(actRecord.name.size()-1);

      // Extract the age.
      // std::stoi returns an integer. We are assuming that
      // it will be small enough to fit into an uint8_t.
      actRecord.age = std::stoi(line.substr(pos).c_str());

      // Debugging aid.. Make sure we have extracted the data correctly.
      std::cout << "ID: " << actRecord.id
         << ", name: " << actRecord.name
         << ", age: " << (int)actRecord.age << std::endl;
      persons.push_back(actRecord);
   }

   // If came here before the EOF was reached, there was an
   // error in the input file.
   if ( !(ifs.eof()) ) {
       std::cerr << "Input format error!" << std::endl;
   } 
}
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>

struct Person {
    unsigned int id;
    std::string forename;
    std::string lastname;
    uint8_t age;
    // ...
};

int main() {
    std::istream& ifs = std::ifstream("file.txt");
    std::vector<Person> persons;
    std::string line;
    int fieldsize[] = {8, 9, 9, 4};

    while(std::getline(ifs, line)) {
        Person person;
        int field = 0, start=0, last;
        std::stringstream fieldtxt;
        fieldtxt.str(line.substr(start, fieldsize[0]));
        fieldtxt >> person.id;
        start += fieldsize[0];
        person.forename=line.substr(start, fieldsize[1]);
        last = person.forename.find_last_not_of(' ') + 1;
        person.forename.erase(last);
        start += fieldsize[1];
        person.lastname=line.substr(start, fieldsize[2]);
        last = person.lastname.find_last_not_of(' ') + 1;
        person.lastname.erase(last);
        start += fieldsize[2];
        std::string a = line.substr(start, fieldsize[3]);
        fieldtxt.str(line.substr(start, fieldsize[3]));
        fieldtxt >> age;
        person.age = person.age;
        persons.push_back(person);
    }
    return 0;
}