在C++中从垂直"块"中的文件读取数据

m528fe3b  于 2022-12-05  发布在  其他
关注(0)|答案(1)|浏览(142)

让我先向你展示我正在阅读的数据的结构(否则很难传达我想要的内容):

Mode:                 1                      2                      3
 Frequency:      -307.68                  57.11                  82.39
 Force Cnst:      0.6182                 0.0089                 0.0283
 Red. Mass:      11.0830                 4.6138                 7.0866
 IR Active:          YES                    YES                    YES
 IR Intens:       17.343                  7.786                  0.017
 Raman Active:       YES                    YES                    YES
               X      Y      Z        X      Y      Z        X      Y      Z
 H         -0.093 -0.046 -0.050    0.002 -0.268  0.324   -0.084 -0.209  0.128
 C         -0.072 -0.019 -0.063    0.003 -0.159  0.195   -0.048 -0.148  0.087
 C         -0.001 -0.046 -0.072    0.007 -0.001  0.001   -0.001 -0.229  0.139
 H         -0.001 -0.120 -0.089    0.006 -0.001  0.001   -0.001 -0.345  0.213
 C          0.073 -0.023 -0.057    0.003  0.158 -0.194    0.047 -0.151  0.090
 H          0.096 -0.052 -0.043    0.002  0.266 -0.322    0.083 -0.214  0.134
 ............................................................................

因此,我想将每个Mode的数据存储在它自己的struct对象(nmode)下,并将每个nmode存储在一个vector中。但是,正如您所看到的,每个Mode的数据都是以这种垂直格式输出的(我无法更改此文件的格式)。
目前,我的解决方案是告诉程序一次获取三个模式的数据,通常使用ifstream(我将在下面发布一个例子)。由于显而易见的原因,这个解决方案在任何不能被3整除的模式数量上都会中断。因此,我的问题是“让程序从这些垂直块中读取任意数量模式的数据的最佳方法是什么?”
以下是当前的解决方案(如果模式数不能被3整除,则该解决方案将失败),以及一个失败的案例:
第一次

enyaitl3

enyaitl31#

不幸的是,没有快速的答案。
你真的需要逐行解析......
这将导致大量的代码。你可以通过编写函数来解析类似的行来优化。但是我们在这里使用完整的方法:
请参阅:

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <iomanip>
using namespace std::string_literals;

// Definition of data structures
struct XYZ {
    char Indicator{};
    double x{};
    double y{};
    double z{};
};

struct Data {
    std::size_t ID{};
    double frequency{};
    double forceCnst{};
    double redMass{};
    bool irActive{};
    double irIntensity{};
    bool ramanActive{};
    std::vector<XYZ> xyz{};
};
// Function to read data in given format
std::vector<Data> readData(std::istream& is) {

    bool parsingOKsoFar{true};

    // Here we will store the resuting values 
    std::vector<Data> data{};

    // First read the modes -------------------------------------------------------
    if (std::string id{}; std::getline(is>>std::ws, id, ':') and (id == "Mode"s)) {

        // Read the rest of the first line to get information about number of modes
        std::string line{}; std::getline(is, line);
        std::istringstream iss{ line };

        // Read and with that count the number of modes
        std::vector<std::size_t> modeIDs{};
        for (size_t m; iss >> m; modeIDs.push_back(m))
            ;
        // Now, we know the number of Modes. Resize the resulting vector accordingly
        data.resize(modeIDs.size());

        // Copy mode IDs into structs
        for (std::size_t i{}; i < data.size(); ++i)
            data[i].ID = modeIDs[i];
    }
    else {
        std::cerr << "\n*** Error: Mode could not be read\n\n";
        parsingOKsoFar = false;
    }

    // Now read frequencies -------------------------------------------------------
    if (std::string id{}; parsingOKsoFar and std::getline(is >> std::ws, id, ':') and (id == "Frequency"s)) {

        // Read the rest of the line to get information about frequencies
        std::string line{}; std::getline(is, line);
        std::istringstream iss{ line };

        // Read the values
        std::vector<double> frequency{};
        for (double f{}; iss >> f; frequency.push_back(f));

        // Sanity check
        if (frequency.size() == data.size())

            // Copy into structs
            for (std::size_t i{}; i < data.size(); ++i)
                data[i].frequency = frequency[i];
        else {
            std::cerr << "\n***Error: Mismatch in number of frequencies and modes\n\n";
            parsingOKsoFar = false;
        }
    }
    else {
        std::cerr << "\n*** Error: Frequency could not be read\n\n";
        parsingOKsoFar = false;
    }

    // Now read force constants -------------------------------------------------------
    if (std::string id{}; parsingOKsoFar and std::getline(is >> std::ws, id, ':') and (id == "Force Cnst"s)) {

        // Read the rest of the line to get information about frequencies
        std::string line{}; std::getline(is, line);
        std::istringstream iss{ line };

        // Read the values
        std::vector<double> forceConst{};
        for (double f{}; iss >> f; forceConst.push_back(f));

        // Sanity check
        if (forceConst.size() == data.size())

            // Copy into structs
            for (std::size_t i{}; i < data.size(); ++i)
                data[i].forceCnst = forceConst[i];
        else {
            std::cerr << "\n***Error: Mismatch in number of force constant and modes\n\n";
            parsingOKsoFar = false;
        }
    }
    else {
        std::cerr << "\n*** Error: Force Constant could not be read\n\n";
        parsingOKsoFar = false;
    }

    // Now read red mass -------------------------------------------------------
    if (std::string id{}; parsingOKsoFar and std::getline(is >> std::ws, id, ':') and (id == "Red. Mass"s)) {

        // Read the rest of the line to get information about frequencies
        std::string line{}; std::getline(is, line);
        std::istringstream iss{ line };

        // Read the values
        std::vector<double> redMass{};
        for (double rm{}; iss >> rm; redMass.push_back(rm));

        // Sanity check
        if (redMass.size() == data.size())

            // Copy into structs
            for (std::size_t i{}; i < data.size(); ++i)
                data[i].redMass = redMass[i];
        else {
            std::cerr << "\n***Error: Mismatch in number of Red Rass and modes\n\n";
            parsingOKsoFar = false;
        }
    }
    else {
        std::cerr << "\n*** Error: Red Mass could not be read\n\n";
        parsingOKsoFar = false;
    }

    // Now read IR Active -------------------------------------------------------
    if (std::string id{}; parsingOKsoFar and std::getline(is >> std::ws, id, ':') and (id == "IR Active"s)) {

        // Read the rest of the line to get information about frequencies
        std::string line{}; std::getline(is, line);
        std::istringstream iss{ line };

        // Read the values
        std::vector<std::string> irActive{};
        for (std::string ira{}; iss >> ira; irActive.push_back(ira));

        // Sanity check
        if (irActive.size() == data.size())

            // Copy into structs
            for (std::size_t i{}; i < data.size(); ++i)
                data[i].irActive = (irActive[i]=="YES"s) ? true : false;
        else {
            std::cerr << "\n***Error: Mismatch in number of IR Active and modes\n\n";
            parsingOKsoFar = false;
        }
    }
    else {
        std::cerr << "\n*** Error: IR Active could not be read\n\n";
        parsingOKsoFar = false;
    }

    // Now read IR Intensity -------------------------------------------------------
    if (std::string id{}; parsingOKsoFar and std::getline(is >> std::ws, id, ':') and (id == "IR Intens"s)) {

        // Read the rest of the line to get information about frequencies
        std::string line{}; std::getline(is, line);
        std::istringstream iss{ line };

        // Read the values
        std::vector<double> irIntens{};
        for (double irt{}; iss >> irt; irIntens.push_back(irt));

        // Sanity check
        if (irIntens.size() == data.size())

            // Copy into structs
            for (std::size_t i{}; i < data.size(); ++i)
                data[i].irIntensity = irIntens[i];
        else {
            std::cerr << "\n***Error: Mismatch in number of IR intensity and modes\n\n";
            parsingOKsoFar = false;
        }
    }
    else {
        std::cerr << "\n*** Error: IR intensity could not be read\n\n";
        parsingOKsoFar = false;
    }

    // Now read Raman Active -------------------------------------------------------
    if (std::string id{}; parsingOKsoFar and std::getline(is >> std::ws, id, ':') and (id == "Raman Active"s)) {

        // Read the rest of the line to get information about frequencies
        std::string line{}; std::getline(is, line);
        std::istringstream iss{ line };

        // Read the values
        std::vector<std::string> ramanActive{};
        for (std::string ra{}; iss >> ra; ramanActive.push_back(ra));

        // Sanity check
        if (ramanActive.size() == data.size())

            // Copy into structs
            for (std::size_t i{}; i < data.size(); ++i)
                data[i].ramanActive = (ramanActive[i] == "YES"s) ? true : false;
        else {
            std::cerr << "\n***Error: Mismatch in number of Raman Active and modes\n\n";
            parsingOKsoFar = false;
        }
    }
    else {
        std::cerr << "\n*** Error: Raman Active could not be read\n\n";
        parsingOKsoFar = false;
    }

    // Now read XYZ header line and throw away -------------------------------------------------------
    if (parsingOKsoFar) {
        std::string line{};
        parsingOKsoFar = !!std::getline(is, line);
    }
    // Read xyz data-------------------------------------------------------
    // Read all lines until we find a "....." pattern
    
    for (std::string line{}; parsingOKsoFar and std::getline(is, line) and (line.substr(0, 5) != "....."s);) {

        // End condition for reading the file
        if (line.substr(1, 5) == "....."s) break;

        std::istringstream iss(line);
        // First read indicator
        if (char indicator{}; iss >> indicator) {

            std::vector<XYZ> xyz{};
            for (XYZ tmp{}; iss >> tmp.x >> tmp.y >> tmp.z; xyz.push_back(tmp));

            // Sanity check
            if (xyz.size() == data.size()) {
                // Copy into structs
                for (std::size_t i{}; i < data.size(); ++i) 
                    data[i].xyz.push_back({ indicator, xyz[i].x, xyz[i].y,xyz[i].z });
            }
            else {
                std::cerr << "\n***Error: Mismatch in number of xyz and modes\n\n";
                parsingOKsoFar = false;
            }
        }
        else 
            std::cerr << "\n***Error: Could not read XYZ\n\n";
    }
    return data;
}

int main() {
    if (std::ifstream ifs{ "r:\\data.txt" }; ifs) {
        std::vector data = readData(ifs);
        for (const Data& d : data) {
            std::cout << "\n\n\n----------------------\nMode:\t" << d.ID << "\nFrequency:\t" << d.frequency << "\nForce Cnst:\t" << d.forceCnst
                << "\nRed. Mass:\t" << d.redMass << "\nIR Active:\t" << (d.irActive ? "YES"s : "NO"s)
                << "\nIR Intens:\t" << d.irIntensity << "\nRaman Active:\t" << (d.ramanActive ? "YES"s : "NO"s) << '\n';
            for (const XYZ& xyz : d.xyz)
                std::cout << "\nX:\t\t" << xyz.x << "\nY:\t\t" << xyz.y << "\nZ:\t\t" << xyz.z << '\n';

        }
    }
    else
        std::cerr << "\n***Error: Could not open source file\n\n";
}

相关问题