diff --git a/ch17/ex17.22/ex17.22/main.cpp b/ch17/ex17.22/ex17.22/main.cpp new file mode 100644 index 00000000..2dcf60d1 --- /dev/null +++ b/ch17/ex17.22/ex17.22/main.cpp @@ -0,0 +1,131 @@ +/*************************************************************************** +* @file main.cpp +* @author Cheng668 +* @date 10 Sept 2016 +* @remark This code is for the exercises from C++ Primer 5th Edition +* @note +***************************************************************************/ +//! +//! Exercise 17.22 +//! Rewrite your phone program so that it allows any number +//! of whitespace characters to separate the three parts of a phone number. + +#include +using std::cerr; +using std::cout; +using std::cin; +using std::endl; +using std::istream; +using std::ostream; + +#include +using std::ifstream; +using std::ofstream; + +#include +using std::istringstream; +using std::ostringstream; + +#include +using std::string; + +#include +using std::vector; + +#include +using std::regex; +using std::sregex_iterator; +using std::smatch; + +struct PersonInfo { + string name; + vector phones; +}; + +bool valid(const smatch& m); +void read_record(istream& is, ostream& ou, vector& people); +void format_record(ostream& os, const string& str, PersonInfo& people); +//! fake function that makes the program compile +string format(const string &num) { return num; } + +int main() +{ + vector people; + + string filename; + cout << "Please input a record file name: "; + cin >> filename; + cout << endl; + ifstream fin(filename); + + if (fin.is_open()) + { + ofstream fout("data\\result.txt", ofstream::trunc); + read_record(fin, fout, people); + } + else + { + cout << "Fail to open file " << filename << endl; + } + system("pause"); + return 0; +} + +bool valid(const smatch& m) +{ + //! if there is an open parenthesis before the area code + if (m[1].matched) + //! the area code must be followed by a close parenthesis + //! and followed immediately by the rest of the number or a space + return m[3].matched + && (m[4].matched == 0 || m[4].str() == " "); + else + //! then there can't be a close after the area code + //! the delimiters between the other two components must match + return !m[3].matched + && m[4].str() == m[6].str(); +} + +void read_record(istream& is,ostream& os, vector& people) +{ + string line, word; //! will hold a line and word from input, respectively + //! read the input a line at a time until cin hits end-of-file (or another error) + while (getline(is, line)) + { + PersonInfo info; //! create an object to hold this record's data + istringstream record(line); //! bind record to the line we just read + record >> info.name; //! read the name + while (getline(record, word)) //! read all the phone numbers includes the space character + format_record(os,word,info); + people.push_back(info); //! append this record to people + } + return; +} + +void format_record(ostream& os, const string& phones, PersonInfo& people) +{ + string phone = + "(\\()?(\\d{3})(\\))?([-.]|\\s*)?(\\d{3})([-.]|\\s*)?(\\d{4})\\b"; + regex r(phone); + ostringstream formatted, badNums; //! objects created on each loop + for (sregex_iterator it(phones.begin(), phones.end(), r), end_it; + it != end_it; ++it) + { + //! check whether the number's formatting is valid + if (!valid(*it)) + //! string in badNums + badNums << " " << it->str(); + else + {//! "writes" to formatted's string + formatted << " " << format(it->str()); + people.phones.push_back(it->str());//!record the vaild phones + } + } + + if (badNums.str().empty()) //! there were no bad numbers + os << people.name << " " //! print the name + << formatted.str() << endl; //! and reformatted numbers + else //! otherwise, print the name and bad numbers + cerr << "input error: " << people.name + << " invalid number(s) " << badNums.str() << endl; +}