创建一个程序来搜索文本文件并提供必要的信息

问题描述 投票:0回答:1

我在用我的代码实现每个选项案例的搜索功能时遇到困难。我不确定如何实际搜索文件以获取我需要代码输出的信息。我将附上我到目前为止的代码。

Cars.h 文件

class Cars {
   protected:
      string make, model;
      double price;
      int miles;
   public:
      Cars(string make, string model, double price, int miles);
      string getMake();
      string getModel();
      double getPrice();
      int getMiles();
      virtual void displayInfo();
};

汽车.cpp文件

Cars::Cars(string make, string model, double price, int miles) {
    this -> make = make;
    this -> model = model;
    this -> price = price;
    this -> miles = miles;
}

string Cars::getMake() {
    return make;
}

string Cars::getModel() {
    return model;
}

double Cars::getPrice() {
    return price;
}

int Cars::getMiles() {
    return miles;
}

void Cars::displayInfo() {
    cout << "Make: " << make << endl;
    cout << "Model: " << model << endl;
    cout << "Price: $" << price << endl;
    cout << "Miles: " << miles << endl;
}

Sedans.h 文件

class Sedans : public Cars {
    private:
        bool hybrid;
    public:
        Sedans(string make, string model, double price, int miles, bool hybrid);
        void displayInfo() override;
};

轿车.cpp 文件

Sedans::Sedans(string make, string model, double price, int miles, bool hybrid) : Cars(make, model, price, miles) {
    this -> make = make;
    this -> model = model;
    this -> price = price;
    this -> miles = miles;
    this -> hybrid = hybrid;
}

void Sedans::displayInfo() {
    Cars::displayInfo();
    cout << "Hybrid: " << (hybrid ? "yes" : "no") << endl;
}

Trucks.h 文件

class Trucks : public Cars {
    private:
        string engine;
    public:
        Trucks(string make, string model, double price, int miles, string engine);
        void displayInfo() override;
};

卡车.cpp 文件

Trucks::Trucks(string make, string model, double price, int miles, string engine) : Cars(make, model, price, miles) {
    this -> make = make;
    this -> model = model;
    this -> price = price;
    this -> miles = miles;
    this -> engine = engine;
}

void Trucks::displayInfo() {
    Cars::displayInfo();
    cout << "Engine: " << engine << endl;
}

主.cpp文件

using namespace std;

int main() {
    ifstream sedansFile;
    sedansFile.open("sedans-1.txt");
    ifstream trucksFile;
    trucksFile.open("trucks-1.txt");

    int option;
    string searchText;
    bool exit = false;

    cout << "**********SEARCH MENU***********" << endl;
    cout << "Search Make..............Press 1" << endl;
    cout << "Search Model.............Press 2" << endl;
    cout << "Search Price.............Press 3" << endl;
    cout << "Search Miles.............Press 4" << endl;
    cout << "Exit.....................Press 5" << endl;

    while (!exit) {
        cout << "\nSelect Option: ";
        cin >> option;

        if (option == 5) {
            exit = true;
            continue;
        }

        cout << "Enter Search Text: ";
        cin.ignore();
        getline(cin, searchText);
        cout << endl;

    }

    return 0;
}

基本上我需要这个输出:

Select Option: 1

Enter Search Text: Toyota
Make: Toyota
Model: Tundra
Miles: 68058
Price: $35348.00
Engine: V6

Make: Toyota
Model: Camry
Miles: 20597
Price: $35348.00
Hybrid: yes

每个选项都会给出不同的搜索条件,并给我匹配的汽车。

文本文件如下:

轿车-1.txt

Toyota Camry 35348 20597 yes
Lexus ES 55609 4693 yes
Honda Accord 22987 11768 no

卡车-1.txt

Toyota Tundra 34271 68058 V6
Ford F-150 55609 9785 V8
Nissan Titan 33990 2677 V6

在这个问题中我不能使用向量或推回。理想情况下,我想要最基本的方法来解决这个问题,而无需过多参与。像初学者编码一样解决这个问题。

c++ inheritance filestream
1个回答
0
投票

我在用我的代码实现每个选项案例的搜索功能时遇到困难。我不确定如何实际搜索文件以获取我需要代码输出的信息。

在这个问题中我不能使用向量或推回。

嗯...不

vector
。好的。因此计划是打开文件,并在每次请求搜索时对所有记录进行顺序扫描。

这个答案重点关注搜索例程。最后给出了其中一个函数

display_trucks_for_given_make
的演示代码。在此过程中,还开发了其他一些功能。

  • 实用函数

    to_int
    to_double
    trim_whitespace_view
    等函数取自我的工具箱。

  • 流提取运算符

    operator>>
    ,对于类
    Trucks
    ,从文件中读取单个记录。

将字符串转换为数字

当从文件中读取

price
miles
时,它们将首先存储为字符串。这些字符串将使用以下函数分别转换为
double
int

注意:评论者正确地指出,美元金额最好转换为便士,并存储为

int
值。否则,舍入误差可能会产生问题。然而,这个答案适用于类型
double
。转换成便士由OP决定。

对于我自己的工作,我使用可以转换任何数字类型的模板函数。模板函数返回一个

std::optional
,转换失败时为空。

对于这个面向初学者的答案,我将放弃模板,并返回

bool
,以指示成功或失败。数字本身在参考参数中返回。

在转换之前,调用

trim_whitespace_view
来去除任何前导或尾随空格。

转换是使用 std::from_chars 进行的,并且必须消耗整个输入字符串。如果剩下任何杂散字符,转换就会失败。

#pragma once
// tbx.utility.h

#include <string>
#include <string_view>

namespace tbx
{
    bool to_double(std::string_view sv, double& value) noexcept;
    bool to_int(std::string_view sv, int& value) noexcept;
    auto to_lower(std::string s) noexcept -> std::string;
    void to_lower_in_place(std::string& s) noexcept;
    auto trim_whitespace_view(std::string_view sv) noexcept -> std::string_view;
}
// end file: tbx.utility.h
// tbx.utility.cpp
#include <algorithm>
#include <charconv>
#include <string>
#include <string_view>
#include "tbx.utility.h"

namespace tbx
{
    //==================================================================
    // to_double
    //==================================================================
    bool to_double(std::string_view sv, double& value) noexcept
    {
        sv = tbx::trim_whitespace_view(sv);
        auto const end{ sv.data() + sv.size() };
        auto [ptr, ec] = std::from_chars(sv.data(), end, value);
        return ec == std::errc{} && ptr == end;
    }
    //==================================================================
    // to_int
    //==================================================================
    bool to_int(std::string_view sv, int& value) noexcept
    {
        sv = tbx::trim_whitespace_view(sv);
        auto const end{ sv.data() + sv.size() };
        auto [ptr, ec] = std::from_chars(sv.data(), end, value);
        return ec == std::errc{} && ptr == end;
    }
    //==================================================================
    // to_lower
    //==================================================================
    std::string to_lower(std::string s) noexcept
    {
        tbx::to_lower_in_place(s);
        return s;
    }
    //==================================================================
    // to_lower_in_place
    //==================================================================
    void to_lower_in_place(std::string& s) noexcept
    {
        std::transform(s.begin(), s.end(), s.begin(),
            [](unsigned char c) {
                return static_cast<char>(std::tolower(c));
            }
        );
    }
    //==================================================================
    // trim_whitespace_view
    //==================================================================
    auto trim_whitespace_view(std::string_view sv) noexcept -> std::string_view
    {
        // Trim leading and trailing whitespace from string_view `sv`.
        auto const first{ sv.find_first_not_of(" \f\n\r\t\v") };
        if (first == std::string_view::npos)
            return {};
        auto const last{ sv.find_last_not_of(" \f\n\r\t\v") };
        enum : std::string_view::size_type { one = 1u };
        return sv.substr(first, (last - first + one));
    }
}
// end file: tbx.utility.cpp

流提取功能

数据文件的结构都是每个字段只有一个“单词”。所有字段都不包含空格。

将来,也许它们可以更改为 CSV 文件(即“逗号分隔值”),这将允许字段包含空格。对于 CSV 文件,用于分隔字段的分隔符(通常)是逗号。

文件

sedans-1.txt
trucks-1.txt
都可以视为 CSV 文件,其中分隔符是空格字符。稍后,只需将分隔符更改为逗号,下面的函数就可以处理真正的 CSV 文件。

下面的示例展示了如何为 Trucks 文件编写流提取运算符。它是作为“隐藏的朋友”实现的。这就是为什么它在类 Trucks 中编码。

如果任何字段提取失败,或者其中一个数字字段无法转换,

operator>>

会抛出

std::runtime_error
我冒昧地向类 

Trucks

添加了默认构造函数。这允许您在调用流提取运算符之前构造一个空的

Trucks
对象。
另请注意,我已包含上一节中的标题 

tbx.utility.h

Trucks 标头末尾声明的四个搜索函数将在下一节中讨论。

#pragma once // Trucks.h #include <iostream> #include <sstream> #include <string> #include "tbx.utility.h" #include "Cars.h" class Trucks : public Cars { private: std::string engine; public: Trucks(); Trucks(std::string make, std::string model, double price, int miles, std::string engine); void displayInfo() override; friend std::istream& operator>> (std::istream& ist, Trucks& truck) { char const delim{ ' ' }; // for CSV, change delim to ',' if (std::string s; std::getline(ist, s)) { std::istringstream iss{ s }; std::string make, model, price_str, miles_str, engine; double price{}; int miles{}; if (!std::getline(iss, make, delim) || !std::getline(iss, model, delim) || !std::getline(iss, price_str, delim) || !tbx::to_double(price_str, price) || !std::getline(iss, miles_str, delim) || !tbx::to_int(miles_str, miles) || !std::getline(iss, engine) ) throw std::runtime_error("Truck: extraction failed: \"" + s + '"'); // "Strong guarantee" - "all or nothing" truck.make = make; truck.model = model; truck.price = price; truck.miles = miles; truck.engine = engine; } return ist; } }; void display_trucks_for_given_make( std::string const& make, std::string const& file_name); void display_trucks_for_given_model( std::string const& model, std::string const& file_name); void display_trucks_for_given_price( double & price, std::string const& file_name); void display_trucks_for_given_miles( int const& miles, std::string const& file_name); // end file: Trucks.h

Sedans 文件的操作符类似。

典型的搜索功能

这是其中一项搜索功能的示例。此命令在卡车文件中搜索给定的

make

,并显示任何匹配卡车的数据。请注意,搜索函数都是

自由函数,
在任何类之外声明。 实用工具箱中的两个函数

tbx::to_lower

tbx::to_lower_in_place
将它们的字符串参数转换为小写。在将车辆品牌与搜索文本进行比较之前,两者都会转换为小写。
每次调用搜索函数时都会重新打开文件。退出搜索功能后,文件将自动关闭(通过其析构函数)。

void display_trucks_for_given_make( std::string make, std::string const& file_name) { tbx::to_lower_in_place(make); std::ifstream ist{ file_name }; if (!ist.is_open()) throw std::runtime_error( "Could not open file: \"" + file_name + '"'); Trucks truck; while (ist >> truck) if (tbx::to_lower(truck.getMake()) == make) truck.displayInfo(); }

其他搜索功能类似。

© www.soinside.com 2019 - 2024. All rights reserved.