[英]Noob C++ I dont quit understand functions and especially how to pass the read file into the struct in a function
[英]I dont get how to read in from a file that has commas and spaces between words. I was told I could use the find and substr functions, I dont know em
这是我收到的反馈,但我不知道该怎么做。
由于每一行都有逗号作为分隔符,因此读取每一行的一种方法是通过 find 函数定位第一个逗号,然后使用 substr 函数获取第一个数据项。 然后再次使用 find 函数定位下一个逗号,然后使用 substr 函数获取第二条数据,...等等。直到到达行尾,然后获取下一行并在 a 中进行相同的处理while 循环。
文本文件:
2415, Target Corporation, 3400 Green Mt Crossing Dr, Shiloh, IL, 62269, 5.7
1705, Starbucks, 1411 W Hwy 50, O'Fallon, IL, 62269, 6.4
3218, ALDI, 1708 N Illinois St, Swansea, IL, 62226, 0.9
4062, Walmart Supercenter, 2608 Green Mt Commons Dr, Belleville, IL, 62221, 4.0
2011, Spectrum Store, 3950 Green Mt Crossing Dr, Shiloh, IL, 62269, 5.4
912, Marco's Pizza, 1838 Central Plaza Dr, Belleville, IL, 62221, 1.8
这就是问题所在。 这是我所做的。
#include<fstream>
#include<iostream>
#include<string>
using namespace std;
const string FILE_NAME = "text.txt";
> this is the Business Structure
struct Business
{
string id;
string name;
string address;
string city;
string state;
string zip;
double distance;
string get_id()
{
string tmp_id = id;
}
> prints a line of business data.
void print()
{
cout << get_id() << ", " << name << ", " << address << ", " << state << ", " << zip << ", " << (distance * 1.6) << endl;
}
};
void DisplayAllBusinessInfo(Business* businesses, int count)
{
for (int i = 0; i < count; ++i)
{
businesses[i].print();
}
}
void SearchByCity(Business* businesses, int count, const string& c_name)
{
for (int i = 0; i < count; ++i)
{
if (businesses[i].city.find(c_name) != string::npos)
{
businesses[i].print();
}
}
}
void SortByDistanceAndSaveToFile(Business* businesses, int count)
{
for (int i = 0; i < count - 1; ++i)
{
for (int j = i + 1; j < count; ++j)
{
if (businesses[j].distance < businesses[i].distance)
auto tmp = businesses[i];
}
}
> Writing Sorted data to the original file
ofstream outFile(FILE_NAME);
for (int i = 0; i < count; ++i)
{
outFile << businesses[i].id << " " << businesses[i].name << " " << businesses[i].address << " " << businesses[i].city << " " << businesses[i].state << " " << businesses[i].zip << " " << businesses[i].distance;
if (i < count - 1)
outFile << endl;
}
outFile.close();
}
> I think im messing up most here in the main function.
int main()
{
ifstream inFile(FILE_NAME);
> Counting number of lines in the file
string line;
int lineCount = 0;
while (getline(inFile, line))
lineCount++;
cout << correct;
>Going back to the start of file as we are at the EOF
inFile.close();
inFile.open(FILE_NAME);
Business *businesses = new Business[lineCount];
int index = 0;
> main part im having trouble with.
while (!inFile.eof())
{
Business bs;
inFile >> bs.id;
inFile >> bs.name;
inFile >> bs.address;
inFile >> bs.city;
inFile >> bs.state;
inFile >> bs.zip;
inFile >> bs.distance;
businesses[index++] = bs;
}
inFile.close();
> Displays the menu and gives a result depending
while (1)
{
cout << "1. Display all business' info" << endl;
cout << "2. Search by city" << endl;
cout << "3. Sort by distance" << endl;
cout << "4. Exit" << endl;
cout << endl << "Please pick a number: ";
int choice;
cin >> choice;
if (choice == 4) exit(0);
string c_name;
switch (choice)
{
case 1:
DisplayAllBusinessInfo(businesses, lineCount);
break;
case 2:
cout << "Enter city name: ";
cin >> c_name;
SearchByCity(businesses, lineCount, c_name);
break;
case 3:
SortByDistanceAndSaveToFile(businesses, lineCount);
break;
default:
cout << "Invalid selction, try again...";
break;
}
cout << endl;
}
return 0;
}
让我们听取您的反馈,使用std::basic_string::find在您使用getline()
读取的行中定位下一个分隔符", "
,然后使用std::basic_string::substr将字符从当前位置提取到std::basic_string::substr
返回的位置。
std::basic_string::find
将返回在字符串中找到分隔符的第一个字符的位置。 您将需要保留 3 个size_t
变量(如果您想在substr
中使用减法表达式,则需要保留 2 个)。 但为了清楚起见,我们将使用 3, pos
字符串中的当前位置, endpos
作为下一个分隔符的位置,并使用pos
和endpos
之间的substr
计算要提取的字符count
。 (我们将调用std::string
保存当前行line
)让我们将文件中打开的流内标记is
.
要从文件中读取整行,您可以执行以下操作:
const std::string DELIM {", "};
...
std::string line{};
size_t count = 0, pos = 0, endpos = 0;;
if (!getline (is, line)) { /* read line validate stream state */
return is;
}
/* locate the next delimiter position in line with substr, validate */
if ((endpos = line.find (DELIM, pos)) == std::string::npos) {
std::cerr << "error: delimiter not found.\n";
is.setstate(std::ios_base::failbit); /* set failbit for return */
return is;
}
count = endpos - pos; /* compute no. of chars to extract */
b.id = line.substr (pos, count); /* extract id with substr */
pos = endpos + DELIM.length(); /* update pos to after delimiter */
由于name
、 address
、 city
、 state
和zip
只是用substr
以完全相同的方式提取,只需复制代码以find
,用substr
提取并更新每个字符串的pos
。
distance
有点不同,原因有两个。 (1) 没有分隔符", "
在它后面找到(它位于行尾)和 (2) 它是一个double
精度值,因此您将使用std::stod转换字符串末尾的值double
。 您可以使用适当的try {} catch() {}
块来验证转换。 在尝试转换之前,您还应该确保zip
之后有要转换的字符。 您可以通过从line.length()
中减去pos
来确保count
为1
或更多。
提取distance
的块可以是:
count = line.length() - pos; /* chars remaining in line */
if (count < 1) { /* validate chars remain for distance */
std::cerr << "error: distance not available.\n";
is.setstate(std::ios_base::failbit);
return is;
}
try { /* convert remaining chars for distance */
b.distance = stod (line.substr (pos, count));
}
catch(std::exception const& e) { /* handle any error in conversion */
std::cerr << "exception::what(): " << e.what() << '\n';
is.setstate(std::ios_base::failbit);
}
为什么选择is
输入流?
C++ 允许您重载>>
和<<
运算符,您可以将它们作为struct
的friend
元函数。 按照惯例, >>
使用is
重载用于流内,而<<
使用os
用于流外。 这使您可以编写结构并提供从保存您想要读取的格式化数据的任何流中填充字段的能力,只需在打开的流上使用>>
就像您从std::cin
读取任何变量一样。 具有填充和输出结构所需的重载的结构定义变为:
struct Business {
std::string id,
name,
address,
city,
state,
zip;
double distance;
friend std::istream& operator >> (std::istream& is, Business& b);
friend std::ostream& operator << (std::ostream& os, const Business& b);
};
>>
的重载将填充结构成员, <<
的重载将以您在<<
重载函数中编写的任何格式输出结构成员。 对于输出示例,您可以执行以下操作:
std::ostream& operator << (std::ostream& os, const Business& b)
{
os << "\nid : " << b.id <<
"\nname : " << b.name <<
"\naddress : " << b.address <<
"\ncity : " << b.city <<
"\nstate : " << b.state <<
"\nzip : " << b.zip <<
"\ndistance: " << b.distance << '\n';
return os;
}
>>
的重载只是每个要提取的字段的find
和substring
以及pos
的更新。 对于distance
,您使用zip
后行中的剩余字符并将字符串传递给stod()
以转换为double
。 它看起来又长又复杂,但实际上它只是重复六次以获取槽zip
然后只是将剩余的字符传递给stod()
,例如
std::istream& operator >> (std::istream& is, Business& b)
{
std::string line{};
size_t count = 0, pos = 0, endpos = 0;;
if (!getline (is, line)) { /* read line validate stream state */
return is;
}
/* locate the next delimiter position in line with substr, validate */
if ((endpos = line.find (DELIM, pos)) == std::string::npos) {
std::cerr << "error: delimiter not found.\n";
is.setstate(std::ios_base::failbit); /* set failbit for return */
return is;
}
count = endpos - pos; /* compute no. of chars to extract */
b.id = line.substr (pos, count); /* extract id with substr */
pos = endpos + DELIM.length(); /* update pos to after delimiter */
/* same thing for name */
if ((endpos = line.find (DELIM, pos)) == std::string::npos) {
std::cerr << "error: delimiter not found.\n";
is.setstate(std::ios_base::failbit);
return is;
}
count = endpos - pos;
b.name = line.substr (pos, count);
pos = endpos + DELIM.length();
/* same thing for address */
if ((endpos = line.find (DELIM, pos)) == std::string::npos) {
std::cerr << "error: delimiter not found.\n";
is.setstate(std::ios_base::failbit);
return is;
}
count = endpos - pos;
b.address = line.substr (pos, count);
pos = endpos + DELIM.length();
/* same thing for city */
if ((endpos = line.find (DELIM, pos)) == std::string::npos) {
std::cerr << "error: delimiter not found.\n";
is.setstate(std::ios_base::failbit);
return is;
}
count = endpos - pos;
b.city = line.substr (pos, count);
pos = endpos + DELIM.length();
/* same thing for state */
if ((endpos = line.find (DELIM, pos)) == std::string::npos) {
std::cerr << "error: delimiter not found.\n";
is.setstate(std::ios_base::failbit);
return is;
}
count = endpos - pos;
b.state = line.substr (pos, count);
pos = endpos + DELIM.length();
/* same thing for zip */
if ((endpos = line.find (DELIM, pos)) == std::string::npos) {
std::cerr << "error: delimiter not found.\n";
is.setstate(std::ios_base::failbit);
return is;
}
count = endpos - pos;
b.zip = line.substr (pos, count);
pos = endpos + DELIM.length();
count = line.length() - pos; /* chars remaining in line */
if (count < 1) { /* validate chars remain for distance */
std::cerr << "error: distance not available.\n";
is.setstate(std::ios_base::failbit);
return is;
}
try { /* convert remaining chars for distance */
b.distance = stod (line.substr (pos, count));
}
catch(std::exception const& e) { /* handle any error in conversion */
std::cerr << "exception::what(): " << e.what() << '\n';
is.setstate(std::ios_base::failbit);
}
return is;
}
一个简短的示例程序,将文件名作为第一个参数从中读取数据,您可以执行以下操作:
int main (int argc, char **argv) {
if (argc < 2) { /* validate at least 1 argument for filename */
std::cerr << "usage: " << argv[0] << " filename\n";
return 1;
}
Business tmp{};
std::vector<Business> business{}; /* vector of struct */
std::ifstream f (argv[1]); /* open file stream */
if (!f.good()) { /* validate file stream state good */
std::cerr << "error: file open failed.\n";
return 1;
}
while ((f >> tmp)) { /* loop filling the tmp struct */
business.push_back (tmp); /* add it to your vector on success */
}
for (const auto& b : business) { /* output each business in vector */
std::cout << b;
}
}
总而言之,您将拥有:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
const std::string DELIM {", "};
struct Business {
std::string id,
name,
address,
city,
state,
zip;
double distance;
friend std::istream& operator >> (std::istream& is, Business& b);
friend std::ostream& operator << (std::ostream& os, const Business& b);
};
std::istream& operator >> (std::istream& is, Business& b)
{
std::string line{};
size_t count = 0, pos = 0, endpos = 0;;
if (!getline (is, line)) { /* read line validate stream state */
return is;
}
/* locate the next delimiter position in line with substr, validate */
if ((endpos = line.find (DELIM, pos)) == std::string::npos) {
std::cerr << "error: delimiter not found.\n";
is.setstate(std::ios_base::failbit); /* set failbit for return */
return is;
}
count = endpos - pos; /* compute no. of chars to extract */
b.id = line.substr (pos, count); /* extract id with substr */
pos = endpos + DELIM.length(); /* update pos to after delimiter */
/* same thing for name */
if ((endpos = line.find (DELIM, pos)) == std::string::npos) {
std::cerr << "error: delimiter not found.\n";
is.setstate(std::ios_base::failbit);
return is;
}
count = endpos - pos;
b.name = line.substr (pos, count);
pos = endpos + DELIM.length();
/* same thing for address */
if ((endpos = line.find (DELIM, pos)) == std::string::npos) {
std::cerr << "error: delimiter not found.\n";
is.setstate(std::ios_base::failbit);
return is;
}
count = endpos - pos;
b.address = line.substr (pos, count);
pos = endpos + DELIM.length();
/* same thing for city */
if ((endpos = line.find (DELIM, pos)) == std::string::npos) {
std::cerr << "error: delimiter not found.\n";
is.setstate(std::ios_base::failbit);
return is;
}
count = endpos - pos;
b.city = line.substr (pos, count);
pos = endpos + DELIM.length();
/* same thing for state */
if ((endpos = line.find (DELIM, pos)) == std::string::npos) {
std::cerr << "error: delimiter not found.\n";
is.setstate(std::ios_base::failbit);
return is;
}
count = endpos - pos;
b.state = line.substr (pos, count);
pos = endpos + DELIM.length();
/* same thing for zip */
if ((endpos = line.find (DELIM, pos)) == std::string::npos) {
std::cerr << "error: delimiter not found.\n";
is.setstate(std::ios_base::failbit);
return is;
}
count = endpos - pos;
b.zip = line.substr (pos, count);
pos = endpos + DELIM.length();
count = line.length() - pos; /* chars remaining in line */
if (count < 1) { /* validate chars remain for distance */
std::cerr << "error: distance not available.\n";
is.setstate(std::ios_base::failbit);
return is;
}
try { /* convert remaining chars for distance */
b.distance = stod (line.substr (pos, count));
}
catch(std::exception const& e) { /* handle any error in conversion */
std::cerr << "exception::what(): " << e.what() << '\n';
is.setstate(std::ios_base::failbit);
}
return is;
}
std::ostream& operator << (std::ostream& os, const Business& b)
{
os << "\nid : " << b.id <<
"\nname : " << b.name <<
"\naddress : " << b.address <<
"\ncity : " << b.city <<
"\nstate : " << b.state <<
"\nzip : " << b.zip <<
"\ndistance: " << b.distance << '\n';
return os;
}
int main (int argc, char **argv) {
if (argc < 2) { /* validate at least 1 argument for filename */
std::cerr << "usage: " << argv[0] << " filename\n";
return 1;
}
Business tmp{};
std::vector<Business> business{}; /* vector of struct */
std::ifstream f (argv[1]); /* open file stream */
if (!f.good()) { /* validate file stream state good */
std::cerr << "error: file open failed.\n";
return 1;
}
while ((f >> tmp)) { /* loop filling the tmp struct */
business.push_back (tmp); /* add it to your vector on success */
}
for (const auto& b : business) { /* output each business in vector */
std::cout << b;
}
}
示例使用/输出
使用文件dat/business.txt
中的数据,运行程序并提供要读取的文件作为第一个命令行参数,将产生:
$ ./bin/business dat/business.txt
id : 2415
name : Target Corporation
address : 3400 Green Mt Crossing Dr
city : Shiloh
state : IL
zip : 62269
distance: 5.7
id : 1705
name : Starbucks
address : 1411 W Hwy 50
city : O'Fallon
state : IL
zip : 62269
distance: 6.4
id : 3218
name : ALDI
address : 1708 N Illinois St
city : Swansea
state : IL
zip : 62226
distance: 0.9
id : 4062
name : Walmart Supercenter
address : 2608 Green Mt Commons Dr
city : Belleville
state : IL
zip : 62221
distance: 4
id : 2011
name : Spectrum Store
address : 3950 Green Mt Crossing Dr
city : Shiloh
state : IL
zip : 62269
distance: 5.4
id : 912
name : Marco's Pizza
address : 1838 Central Plaza Dr
city : Belleville
state : IL
zip : 62221
distance: 1.8
看看事情,如果你有问题,请告诉我。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.