【问题标题】:Strange issue reading from a CSV从 CSV 读取的奇怪问题
【发布时间】:2022-01-18 02:41:03
【问题描述】:

我正在尝试编写一个程序,允许用户通过使用名称、原子序数或符号搜索来搜索元素周期表上的任何元素。目前名称和原子序数工作正常,但是当我尝试复制和粘贴符号的代码时,它突然不起作用。甚至在 cout 中进行硬编码

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

using namespace std;

std::vector<std::string> readAtomicNumber(std::string file_name,std::string search_term);
std::vector<std::string> readName(std::string file_name,std::string search_term);
std::vector<std::string> readSymbol(std::string file_name,std::string search_term);

int main()
{
    
    int searchchoice;
    int AtomicNumber;
    string Name;
    string Symbol;
    string term;
    
    cout << "How will you be searching?\nYou may search using;\n1 = Element Name\n2 = Element Symbol\n3 = Atomic Number\n4 = Show me the entire Periodic Table.\n\n";
    cin  >> searchchoice;
    
    if(searchchoice == 4)
    {
        //something here to cout the entire periodic table
    }
    else if(searchchoice == 3)
    {
        cout << "\n\nWhat is the Atomic Number of the Element you are searching for?\n";
        cin >> term;
    }
    else if(searchchoice == 2)
    {
        cout << "\n\nWhat is the Symbol of the Element you are searching for?\n";            // going to need something to return
        cin >> term;                                                                         // "that is not a name/atomic number etc"
    }                                                                                        // incase of a false input
    else if(searchchoice == 1)   
    {
        cout << "\n\nWhat is the Name of the Element you are searching for?\n";
        cin >> term;
    }
    else
    {
        cout << "\n\nError. Please re-run the program, and input 1, 2, or 3.\n";
        return 0;
    }
    
    if(searchchoice == 3)
    {
        std::vector<std::string> data = readAtomicNumber("PeriodicTableupdated",term);                  //atomic number
    }
    else if(searchchoice == 2)
    {
        std::vector<std::string> data = readSymbol("PeriodicTableupdated",term);                         //symbol
    }                                                                                        
    else if(searchchoice == 1)   
    {
        std::vector<std::string> data = readName("PeriodicTableupdated",term);                           //name
    }

    
return 0;
}

std::vector<std::string> readAtomicNumber(std::string file_name,std::string search_term)            //READ ATOMIC NUMBER
{
    std::vector<std::string> record;
    
    std::ifstream file;
    file.open(file_name);
    
    bool found_record = false;
    
    std::string field_one; //atomic number
    std::string field_two; // name
    std::string field_three; // symbol
    std::string field_four;
    
    while(getline(file,field_one,',') && !found_record)
    {
        getline(file,field_two,',');
        getline(file,field_three,',');
        getline(file,field_four,'\n');
        if(field_one == search_term)
        {
            found_record = true;
            record.push_back(field_one);
            record.push_back(field_two);
            record.push_back(field_three);
            record.push_back(field_four);
        }
    }
    
        std::cout << "\nThat Element is: " << record[1] << "\nAtomic Number:\tName:\t\tSymbol:\t\tAtomic Mass:\n" << record[0] << "\t\t" << record[1] << "\t" << record[2] << "\t\t" << record[3];
    return record;
}

std::vector<std::string> readName(std::string file_name,std::string search_term)            // READ NAME
{
    std::vector<std::string> record;
    
    std::ifstream file;
    file.open(file_name);
    
    bool found_record = false;
    
    std::string field_one; //atomic number
    std::string field_two; // name
    std::string field_three; // symbol
    std::string field_four;
    
    while(getline(file,field_two,',') && !found_record)
    {
        getline(file,field_one,',');
        getline(file,field_three,',');
        getline(file,field_four,'\n');
        if(field_one == search_term)
        {
            found_record = true;
            record.push_back(field_one);
            record.push_back(field_two);
            record.push_back(field_three);
            record.push_back(field_four);
        }
    }
    
        std::cout << "\nThat Element is: " << record[0] << "\nAtomic Number:\t\tName:\t\tSymbol:\t\tAtomic Mass:\n" << record[1] << "\t\t\t" << record[0] << "\t" << record[2] << "\t\t" << record[3];
    return record;
}

std::vector<std::string> readSymbol(std::string file_name,std::string search_term)            // READ SYMBOL
{
    std::vector<std::string> record;
    
    std::ifstream file;
    file.open(file_name);
    
    bool found_record = false;
    
    std::string field_one; //atomic number
    std::string field_two; // name
    std::string field_three; // symbol
    std::string field_four;
    
    while(getline(file,field_three,',') && !found_record)
    {
        getline(file,field_one,',');
        getline(file,field_two,',');
        getline(file,field_four,'\n');
        if(field_three == search_term)
        {
            found_record = true;
            record.push_back(field_one);
            record.push_back(field_two);
            record.push_back(field_three);
            record.push_back(field_four);
        }
    }
    
        std::cout << "\nThat Element is: " << record[2] << "\nAtomic Number:\t\tName:\t\tSymbol:\t\tAtomic Mass:\n" << record[0] << "\t\t\t" << record[1] << "\t" << record[2] << "\t\t" << record[3];
    return record;
}

我使用的元素周期表 csv 有 118 个元素,因此我将只包括前 10 个元素。

AtomicNumber,Element,Symbol,AtomicMass
1,Hydrogen,H,1.007
2,Helium,He,4.002
3,Lithium,Li,6.941
4,Beryllium,Be,9.012
5,Boron,B,10.811
6,Carbon,C,12.011
7,Nitrogen,N,14.007
8,Oxygen,O,15.999
9,Fluorine,F,18.998
10,Neon,Ne,20.18

【问题讨论】:

  • 您是否尝试过在调试器中逐行运行代码,同时监控所有变量的值,以确定您的程序在哪个点停止按预期运行?如果您没有尝试过,那么您可能想阅读以下内容:What is a debugger and how can it help me diagnose problems? 您可能还想阅读以下内容:How to debug small programs?
  • 我对复制+粘贴其他代码的代码量感到困扰。这是创建在某些方面有效但在其他方面无效的代码的常见方法。为什么readSymbolfield_one 之前读取field_three?这闻起来像是复制+粘贴错误。
  • 在我给出答案之前,请在互联网上搜索“C++ class read CSV”。
  • 如果您的搜索失败,则 record 为空并且您的代码具有未定义的行为。
  • @DrewDormann 我这样做是因为我认为这就是我试图读取符号的 csv 的引用方式。符号是 field_three,而 field_one 是原子序数。我错了吗?

标签: c++ arrays vector record getline


【解决方案1】:

我强烈建议不要使用并行数组,而是使用对数据(记录)建模的结构向量。让我们将记录定义为一个文本行上的数据,减去分隔符。

struct Element
{
    unsigned int atomic_number;
    std::string  name;
    std::string  symbol;
    double       atomic_mass;
    friend std::istream& operator>>(std::istream& input, Element& e);
};

std::istream& operator>>(std::istream& input, Element& e)
{
    std::string text_record;
    std::getline(input, text_record);
    std::istringstream text_stream(text_record);
    text_stream >> e.atomic_number;
    char comma;
    text_stream >> comma;
    std::getline(text_stream, e.name, ',');
    std::getline(text_stream, e.symbol, ',');
    text_stream >> e.atomic_mass;
    return input;
};

上述代码对 Element 进行建模并重载 operator&gt;&gt; 以读取 Element

您的数据输入可能如下所示:

std::vector<Element> database;
Element e;
//... open file.
while (file >> e)
{
    database.push_back(e);  // Append to database;
}

然后您可以通过蛮力搜索数据库。

编辑 1:索引表
索引表是按关键成员排序并包含到数据库的链接或偏移量的表。这将允许您通过键进行搜索,而无需求助于数据库。

我们需要一个按名称进行比较的索引表:

std::map<string, unsigned int> index_by_name;

下面是对输入的修改:

unsigned int db_index = 0;
while (file >> e)
{
    database.push_back(e);
    index_by_name[e.name] = db_index;
    ++db_index;
}

因此,要在数据库中搜索 Sodium,您可以:

unsigned int sodium_index = index_by_name.at("Sodium");
Element sodium_element = database.at(sodium_index);

如果没有索引表,您将不得不进行线性搜索,或者对数据库进行排序然后进行二分搜索(或基于排序内容的其他搜索)。

【讨论】:

    【解决方案2】:
    std::vector<std::string> readSymbol(std::string file_name, std::string search_term)            // READ SYMBOL
    {
        std::vector<std::string> record;
    
        std::ifstream file;
        file.open(file_name);
    
        bool found_record = false;
    
        std::string field_one; //atomic number
        std::string field_two; // name
        std::string field_three; // symbol
        std::string field_four;
    
        while (getline(file, field_three, ',') && !found_record)
        {
            getline(file, field_one, ',');
            getline(file, field_two, ',');
            getline(file, field_four, '\n');
            if (field_three == search_term)
            {
                found_record = true;
                record.push_back(field_one);
                record.push_back(field_two);
                record.push_back(field_three);
                record.push_back(field_four);
            }
        }
    
        std::cout << "\nThat Element is: " << record[2] << "\nAtomic Number:\t\tName:\t\tSymbol:\t\tAtomic Mass:\n" << record[0] << "\t\t\t" << record[1] << "\t" << record[2] << "\t\t" << record[3];
        return record;
    }
    

    在这部分中,您实际上将直到, 的第一个字符串分配给field_three

    但第一个字符串实际上是 行号,因为您的文件结构是:

    lineNumber , Name, Symbol, Mass
    

    所以(field_three == search_term)的比较实际上是lineNumber and Symbol之间的比较,这不合逻辑。

    当您调试时,您会更好地看到变量。

    我会在下面放一张截图。

    【讨论】:

    • 我在这之后遇到了麻烦,在第 37 行,用户将一个符号输入到字符串术语中,然后在第 56 行将其作为 search_term 调用。那么这不是(field_three == term)吗?
    • @doctorofmadness search_term 已经是一个符号(在屏幕截图中,我在提示符中输入了He),不过field_three 只是一个整数。 (在此屏幕截图中为 2)。因此,您基本上将字符串与返回 false 的整数 (2 == "He") 进行比较。然后你在读取记录[2]时遇到分段错误,因为记录是一个空向量。
    猜你喜欢
    • 1970-01-01
    • 2014-03-24
    • 2011-03-11
    • 1970-01-01
    • 2010-12-17
    • 2016-01-10
    • 2020-02-08
    • 1970-01-01
    相关资源
    最近更新 更多