如何使用istream读取带空字段的格式化输入

时间:2018-04-03 01:03:36

标签: c++ istream formatted-input

我想用std :: istream或fscanf()读取指定格式的文件。

文件的每一行都包含几个字段。字段可以是char,float或整数。每个字段都有固定的宽度,可能是空的。有没有办法阻止std :: istream忽略空字段?

=============================================== ==================

以下是详细说明。

我正在编写解析pdb样式文件的程序。 部分格式遵循以下格式: 记录格式

COLUMNS        DATA  TYPE    FIELD        DEFINITION
------------------------------------------------------------------------------------
 1 -  6        Record name   "ATOM  "
 7 - 11        Integer       serial       Atom  serial number.
13 - 16        Atom          name         Atom name.
17             Character     altLoc       Alternate location indicator.
18 - 20        Residue name  resName      Residue name.
22             Character     chainID      Chain identifier.
23 - 26        Integer       resSeq       Residue sequence number.
27             AChar         iCode        Code for insertion of residues.
31 - 38        Real(8.3)     x            Orthogonal coordinates for X in Angstroms.
39 - 46        Real(8.3)     y            Orthogonal coordinates for Y in Angstroms.
47 - 54        Real(8.3)     z            Orthogonal coordinates for Z in Angstroms.
55 - 60        Real(6.2)     occupancy    Occupancy.
61 - 66        Real(6.2)     tempFactor   Temperature  factor.
77 - 78        LString(2)    element      Element symbol, right-justified.
79 - 80        LString(2)    charge       Charge  on the atom.

这是实际输入的一部分:

ATOM      1  N   MET A   0      24.512   8.259  -9.688  1.00 33.83           N  
ATOM      2  CA  MET A   0      24.523   9.740  -9.865  1.00 32.90           C  
ATOM      3  C   MET A   0      25.889  10.228 -10.330  1.00 31.90           C  
ATOM      4  O   MET A   0      26.886   9.516 -10.198  1.00 32.07           O  
ATOM      5  CB  MET A   0      24.143  10.414  -8.560  1.00 34.34           C  
ATOM      6  CG  MET A   0      24.891   9.880  -7.378  1.00 35.66           C  
ATOM      7  SD  MET A   0      24.111  10.428  -5.871  1.00 38.66           S  
ATOM      8  CE  MET A   0      24.454  12.221  -5.988  1.00 36.36           C  
ATOM      9  N   VAL A   1      25.922  11.435 -10.891  1.00 30.10           N  
ATOM     10  CA  VAL A   1      27.161  12.020 -11.393  1.00 27.92           C  
ATOM     11  C   VAL A   1      27.260  13.522 -11.114  1.00 26.21           C  
ATOM     12  O   VAL A   1      26.304  14.278 -11.304  1.00 26.54           O  
ATOM     13  CB  VAL A   1      27.312  11.769 -12.919  1.00 27.99           C  
ATOM     14  CG1 VAL A   1      28.557  12.455 -13.466  1.00 27.68           C  
ATOM     15  CG2 VAL A   1      27.395  10.282 -13.189  1.00 28.05           C  

您可能会注意到,某些字段为空。例如,第17列的altLoc(备用位置)是可选的,第79-80栏的费用通常是丢失的。

有时字段不是分开的,因为名称altLoc和resName字段可能形成类似CG1AVAL的东西,实际上是CG1,A和VAL。

我正在尝试用C ++实现该程序。我尝试了两个运算符>>和fscanf但未能找到解决方案来读取结构Atom的输入。

struct Atom
{
    std::string recordName{ 6 };
    int serial;
    std::string name{ 4 };
    char altLoc;
    std::string resName{ 3 };
    char chainID;
    int resSeq;
    char iCode;
    double x;
    double y;
    double z;
    double occupancy;
    double tempFactor;
    char segment;
    char element;
    char charge;
};

setw(size_t n)不能像我预期的那样工作,而且由于我必须使用41.9GB的输入,因此性能很重要,所以我不想在字符串中添加太多像getline()这样的输入。然后解析该字符串。这是我失败的尝试:

ChainReader & ChainReader::operator>>(Atom & atom)
{
    *stream //stream is a pointer to stream, which is a member of ChainReader
        >> std::setw(4) >> atom.recordName
        >> std::setw(7) >> atom.serial
        >> std::setw(5) >> atom.name
        >> std::setw(1) >> atom.altLoc
        >> std::setw(3) >> atom.resName
        >> std::setw(2) >> atom.chainID
        >> std::setw(4) >> atom.resSeq
        >> std::setw(1) >> atom.iCode
        >> std::setw(11) >> atom.x
        >> std::setw(8) >> atom.y
        >> std::setw(8) >> atom.z
        >> std::setw(6) >> atom.occupancy
        >> std::setw(6) >> atom.tempFactor
        >> std::setw(10) >> atom.segment
        >> std::setw(2) >> atom.element
        >> std::setw(2) >> atom.charge;
    return *this;
}

更新

提出一个getline和字符串解析的解决方案。工作,仍在测试性能。

ChainReader & ChainReader::operator>>(Atom & atom)
{
    std::string line;
    line.reserve(80);
    std::getline(*stream, line);
    atom.recordName = line.substr(0, 4);
    atom.serial = std::stoi(line.substr(6, 5));
    atom.name = line.substr(12, 4);
    atom.altLoc = line[16];
    atom.resName = line.substr(17, 3);
    atom.chainID = line[21];
    atom.resSeq = std::stoi(line.substr(22, 4));
    atom.iCode = line[26];
    atom.x = std::stod(line.substr(30, 8));
    atom.y = std::stod(line.substr(38, 8));
    atom.z = std::stod(line.substr(46, 8));
    atom.occupancy = std::stod(line.substr(54, 6));
    atom.tempFactor = std::stod(line.substr(60, 6));
    atom.segment = line[75];
    atom.element = line[77];
    atom.charge = line[79];
    return *this;
}

更新2: 该程序读取ASTRAL数据集中的276231个链,并计算沿链的二面角。完全占用10237134毫秒,或3小时。数据集大约为42GB,因此性能完全可以接受。

0 个答案:

没有答案