繁体   English   中英

我不知道如何从单词之间有逗号和空格的文件中读取。 有人告诉我可以使用 find 和 substr 函数,我不知道

[英]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作为下一个分隔符的位置,并使用posendpos之间的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 */

由于nameaddresscitystatezip只是用substr以完全相同的方式提取,只需复制代码以find ,用substr提取并更新每个字符串的pos

distance有点不同,原因有两个。 (1) 没有分隔符", "在它后面找到(它位于行尾)和 (2) 它是一个double精度值,因此您将使用std::stod转换字符串末尾的值double 您可以使用适当的try {} catch() {}块来验证转换。 在尝试转换之前,您还应该确保zip之后有要转换的字符。 您可以通过从line.length()中减去pos来确保count1或更多。

提取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++ 允许您重载>><<运算符,您可以将它们作为structfriend元函数。 按照惯例, >>使用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;
}

>>的重载只是每个要提取的字段的findsubstring以及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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM