我在用我的代码实现每个选项案例的搜索功能时遇到困难。我不确定如何实际搜索文件以获取我需要代码输出的信息。我将附上我到目前为止的代码。
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
在这个问题中我不能使用向量或推回。理想情况下,我想要最基本的方法来解决这个问题,而无需过多参与。像初学者编码一样解决这个问题。
我在用我的代码实现每个选项案例的搜索功能时遇到困难。我不确定如何实际搜索文件以获取我需要代码输出的信息。
在这个问题中我不能使用向量或推回。
嗯...不
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();
}
其他搜索功能类似。