Hey guys, I am studying the problems solving with C++ book. However, I am stuck
ID: 3557839 • Letter: H
Question
Hey guys,
I am studying the problems solving with C++ book. However, I am stuck in one of the book's projects and I need some help please. Basically I have a file which is called address.xmi. This file contains some information.( I will copy and paste the file in here). However this project has two parts; the first one is to write a small program outputting the names and address of everyone in Palmdale(a city in the address file). The second part is to write a small program that reads in the file address.xmi and output the name and address of everyone whose zip code falls within the range 90210 through 90214.
the file
<?xml version="1.0"?>
<address_book>
<contact>
<name>George Clooney</name>
<street>1042 El Camino Real</street>
<city>Beverly Hills</city>
<state>CA</state>
<zip>90214</zip>
</contact>
<contact>
<name>Cathy Pearl</name>
<street>405 A St.</street>
<city>Palmdale</city>
<state>CA</state>
<zip>93352</zip>
</contact>
<contact>
<name>Paris Hilton</name>
<street>200 S. Elm St.</street>
<city>Beverly Hills</city>
<state>CA</state>
<zip>90212</zip>
</contact>
<contact>
<name>Wendy Jones</name>
<street>982 Boundary Ave.</street>
<city>Palmdale</city>
<state>CA</state>
<zip>93354</zip>
</contact>
</address_book>
in case you have the book it is chapter 8 project 14 page 491.
This is my first question, thus I am sorry for any mistakes.
I will appreciate any help :)
thanks a lot
Explanation / Answer
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
// Reads the next contact record, returning true if found or false if no
// more records are available
bool read_next_contact(ifstream &in, string &name, string &street,
string &city, string &state, string &zip);
// Prints the given contact
void print_contact(string &name, string &street,
string &city, string &state, string &zip);
// Prints all of the addresses with the given city
void find_city(char file_name[], char city[]);
// Prints all of the addresses in the given range of zip codes (inclusive)
void find_in_zip_range(char file_name[], int zip1, int zip2);
// Returns true if tofind is a substring of str. Will return false if
// tofind is empty. This is equivalent to:
//
// (str.find(tofind) != string::npos)
//
bool contains(string str, string tofind);
int main()
{
// Look for addresses in Palmdale
cout << "Addresses in Palmdale: " << endl << endl;
find_city("address.xml", "Palmdale");
// Then look for addresses with zip codes between 90210 and 90214
cout << endl << "Addresses with zip codes between 90210 and 90214: "
<< endl << endl;
find_in_zip_range("address.xml", 90210, 90214);
return 0;
}
// Prints all of the addresses with the given city
void find_city(char file_name[], char city_to_find[])
{
ifstream in;
string name, street, city, state, zip;
in.open(file_name);
if (in.fail())
{
cout << "Could not open input file" << endl;
exit(1);
}
while (read_next_contact(in, name, street, city, state, zip))
{
if (city == city_to_find)
{
print_contact(name, street, city, state, zip);
}
}
in.close();
}
// Prints all of the addresses in the given range of zip codes (inclusive)
void find_in_zip_range(char file_name[], int zip1, int zip2)
{
ifstream in;
string name, street, city, state, zip;
in.open(file_name);
if (in.fail())
{
cout << "Could not open input file" << endl;
exit(1);
}
while (read_next_contact(in, name, street, city, state, zip))
{
int zipInt = atoi(zip.c_str());
if ((zipInt >= zip1) && (zipInt <= zip2))
{
print_contact(name, street, city, state, zip);
}
}
in.close();
}
// Reads the next contact record, returning true if found or false if no
// more records are available
bool read_next_contact(ifstream &in, string &name, string &street,
string &city, string &state, string &zip)
{
string line;
bool result = false;
// Clear the strings
name.erase(0, name.length());
street.erase(0, street.length());
city.erase(0, city.length());
state.erase(0, state.length());
zip.erase(0, zip.length());
// Find the next contact record, or the end of the file
getline(in, line);
while ((! contains(line, "contact")) &&
(! contains(line, "/address_book")))
{
getline(in, line);
}
if (! contains(line, "/address_book"))
{
// Keep going until we hit the </contact> tag
getline(in, line);
while (! contains(line, "/contact"))
{
int tagStart = line.find("<");
int tagEnd = line.find(">");
if (contains(line, "<"))
{
string tag = line.substr(tagStart + 1, tagEnd - tagStart - 1);
int closeTag = line.find("</");
string value = line.substr(tagEnd + 1, closeTag - tagEnd - 1);
if (tag == "name")
name = value;
else if (tag == "street")
street = value;
else if (tag == "city")
city = value;
else if (tag == "state")
state = value;
else if (tag == "zip")
zip = value;
}
getline(in, line);
}
result = true;
}
return result;
}
void print_contact(string &name, string &street,
string &city, string &state, string &zip)
{
cout << name << endl;
cout << street << endl;
cout << city << ", " << state << " " << zip << endl << endl;
}
// Returns true if tofind is a substring of str. Will return false if
// tofind is empty.
bool contains(string str, string tofind)
{
// The string class provides an easier way of doing this, but it
// is not discussed in the text. The standard str.find(tofind)
// member function will return a value between 0 and one less than
// the length of the string if tofind is a substring of str. Otherwise,
// find will return the special value string::npos. Hence this
// function could be implemented in a single line as:
//
// return (str.find(tofind) != string::npos);
bool found = false;
int lastPosToCheck = str.length() - tofind.length();
if (tofind.length() > 0)
{
for (int i = 0; (i <= lastPosToCheck) && (! found); i++)
{
// See if we can find a match for the first character
if (str[i] == tofind[0])
{
// Then iterate through any remaining characters
// in tofind
bool ok = true;
for (int j = 1; (j < tofind.length()) && ok; j++)
{
ok = (str[i + j] == tofind[j]);
}
found = ok;
}
}
}
return found;
}