/*Tord Hjalt 2023 Xtructarix_E-mail-list handler 2 L/l: Change to lower case. S/s: Subtract one list from another. J/j: Join two lists, remove redundancies. C/c: Count the number of strings in a file. A/a: Alphabetic (mostly) sort file contents. E/e: Extract e-mail addresses from a text mass. D/e: Sort by department. N/n: Extract full names from e-mails. */ #include #include //files #include #include // std::replace, sort #include //blocks inserting duplicates #include #include using namespace std; //declare function that changes to all lowercase string: string fCaser(string S); //declare function that changes name to Name: string fUpperN(string A); //fancy colors: void setcolor(unsigned int color); int main() { string sQuit; vectorvAllNames; vectorvResponders; unordered_set set; string word; while(1) { setcolor(12);// 12 = red cout << "***********************" << endl; cout << "Xtructarix E-mail-list handler" << endl; cout << "_____version 2___________" << endl; setcolor(10);//green cout << "A/a: Alphabetically sort file contents." << endl; cout << "C/c: Count the number of strings in a file." << endl; cout << "D/d: Sort by Department name." << endl; cout << "E/e: Extract e-mail addresses from a text." << endl; cout << "J/j: Join two lists, remove redundancies." << endl; cout << "L/l: Change to lower case." << endl; cout << "N/n: Extract full names from e-mails." << endl; cout << "S/s: Subtract one list from another." << endl; cout << " " << endl; cout << "H/h: Helpful tips." << endl; cout << "Q/q to quit" << endl; cout << " " << endl; setcolor(12); //12 = red cout << "Tord Hjalt 2023" << endl; cout << "***********************" << endl; setcolor(10);//green cin >> sQuit; if((sQuit == "Q")||(sQuit == "q")) { return 0; } else if ((sQuit == "S")||(sQuit == "s")) { cout << "Subtract a list from another," << endl; cout << "for e.g. a Reminder List of e-mail addresses." << endl; cout << "The new list are of people who have not responded." << endl; cout << "NOTE: CASE-SENSITIVE! (better change all to lower case first)" << endl; cout << "(I will add the .txt suffix in names)." << endl; string sOutRem; //load vector with all names: cout << "Enter name of list of all." << endl; cin >> sQuit; sOutRem = sQuit; sQuit = sQuit + ".txt"; ifstream fin_A(sQuit); if(!fin_A) { cout << "can't find file " << sQuit << endl; cout << "Exiting..." << endl; Sleep(2000); return 0; } else { while(fin_A >> sQuit) { vAllNames.push_back(sQuit); } fin_A.close(); cout << endl; } //load another vector with those that responded: cout << "Enter name of list of responders." << endl; cout << "(I will add the .txt suffix in names)." << endl; cin >> sQuit; sOutRem = sOutRem + "-" + sQuit; sQuit = sQuit + ".txt"; ifstream fin2_A(sQuit); if(!fin2_A) { cout << "can't find file " << sQuit << endl; cout << "Exiting..." << endl; Sleep(2000); return 0; } else { while(fin2_A >> sQuit) { vResponders.push_back(sQuit); } fin2_A.close(); cout << endl; } //check that done in right order, the first list //should always be larger...: if(vResponders.size() > vAllNames.size()) { cout << "Oops! Your first list should always be larger!" << endl; cout << "You attempted: " << sOutRem << endl; cout << "Shutting down..." << endl; Beep(400,500);Beep(800,500); Sleep(4000); return(0); } string sMatch; vectorvMatches; //mark all matches with % symbol: for(int i = 0; i < vResponders.size(); i++) { for(int j = 0; j < vAllNames.size(); j++) { //if a match, that should be excluded from the remind list if(vResponders[i] == vAllNames[j]) { sMatch = vResponders[i]; //= this person has responded vMatches.push_back(sMatch); //stores all responders of the All list //so they can be removed later //Cannot remove from here, that would create bug //by changing a list that is in use. } }//end for j }//end for 1 //Now remove responders from the All list and thus create the Remind list: for(int m = 0; m < vMatches.size(); m++) { sQuit = vMatches[m]; string sWap = "%"; replace (vAllNames.begin(), vAllNames.end(), sQuit, sWap); //responders marked by a % }//end for m //print Remind list to file: ofstream fout("Reminders.txt"); if(!fout) { cout << "cannot write output file" << endl; cout << "Exiting..." << endl; Sleep(2000); return 0; } sQuit = "%"; for(int n = 0; n < vAllNames.size(); n++) //no need to create new list, this is reduced already { //remove all %, they have already responded: if((vAllNames[n]) == sQuit) Beep(800,50); else fout << vAllNames[n] << endl; } fout.close(); cout << "Remind list created. (Reminders.txt)" << endl; cout << "by substracting: " << sOutRem << endl; cout << endl; //Sleep(2000); //clean-up: vAllNames.erase(vAllNames.begin(), vAllNames.end()); vResponders.erase(vResponders.begin(), vResponders.end()); vMatches.erase(vMatches.begin(), vMatches.end()); sQuit = ""; }//end option S else if ((sQuit == "J")||(sQuit == "j")) { string sFile_1; string sFinal; cout << "Combines two lists," << endl; cout << "removes redundant strings." << endl; cout << "NOTE: CASE-SENSITIVE! (better change all to lower case first)" << endl; cout << endl; cout << "file name 1?" << endl; cout << "(I will add the .txt suffix in names)." << endl; cin >> sFile_1; sFinal = sFile_1; sFile_1 = sFile_1 + ".txt"; ifstream fin1(sFile_1); if(!fin1) { cout << "no such file " << sFile_1 << endl; cout << "Exiting..." << endl; Sleep(2000); return 0; } else { while (fin1 >> word) { set.insert(word); //unordered_set has a function to bar duplicate entry } fin1.close(); } string sFile_2; cout << "file name 2?" << endl; cout << "(I will add the .txt suffix in names)." << endl; cin >> sFile_2; sFinal = sFinal + "_" + sFile_2; sFile_2 = sFile_2 + ".txt"; ifstream fin2(sFile_2); if(!fin2) { cout << "no such file " << sFile_2 << endl; cout << "Exiting..." << endl; Sleep(2000); return 0; } else { while (fin2 >> word) { set.insert(word); //unordered_set has a function to bar duplicate entry } fin2.close(); } sFinal = sFinal + ".txt"; ofstream fout2(sFinal); if(!fout2) { cout << "cannot write output file" << sFinal<< endl; cout << "Exiting..." << endl; Sleep(2000); return 0; } else { for (const string& word : set) { fout2 << word << endl; } fout2.close(); cout << "Done combining files, output is in the file " << sFinal << endl; } cout << endl; //clean-up: set.erase(set.begin(), set.end()); }//end option J else if ((sQuit == "L")||(sQuit == "l")) { string sBert; vectorvAllNames; vectorvCleanedNames; //read file with e-mail addresses, put in string vector: cout << "Input file name. All upper case letters" << endl; cout << "(except non-English)" << endl; cout << "will be replaced with lower case letters." << endl; cout << "(I will add the .txt suffix in names)." << endl; cin >> sBert; string sOutput = sBert + "_low.txt"; sBert = sBert + ".txt"; ifstream fin(sBert); if(!fin) { cout << "can't find file " << sBert << endl; cout << "Shutting down..." << endl; Sleep(2000); return 0; } else { while(fin >> sBert) { vAllNames.push_back(sBert); } fin.close(); cout << endl; } string sHuell; for(int j = 0; j < vAllNames.size(); j++) { sHuell = vAllNames[j]; sBert = fCaser(sHuell); //replaces with small cases vCleanedNames.push_back(sBert); }//end for j ofstream fout7(sOutput); if(!fout7) { cout << "can't write file " << sOutput << endl; cout << "Shutting down..." << endl; Sleep(2000); return 0; } //print all-lower-case e-mail addresses to file: for(int p = 0; p < vCleanedNames.size(); p++) { fout7 << vCleanedNames[p] << endl; }//end for p fout7.close(); //clean-up: remove("Tempstring.txt"); remove("Cleanstring.txt"); vAllNames.erase(vAllNames.begin(), vAllNames.end()); vCleanedNames.erase(vCleanedNames.begin(), vCleanedNames.end()); cout << "It is done, see file " << sOutput << endl; cout << endl; }//end option L else if ((sQuit == "C")||(sQuit == "c")) { string sDaFile; string sDaString; cout << "Counts number of entries in which file?" << endl; cout << "(I will add the .txt suffix.)" << endl; cin >> sDaFile; sDaFile = sDaFile + ".txt"; ifstream fin8(sDaFile); if(!fin8) { cout << "can't find file " << sDaFile << endl; cout << "Shutting down..." << endl; Sleep(2000); return 0; } else { while(fin8 >> sDaString) { vAllNames.push_back(sDaString); } fin8.close(); cout << endl; } cout << "The list " << sDaFile << " contains " << vAllNames.size() << " strings." << endl; cout << endl; //Sleep(5000); //clean-up: vAllNames.erase(vAllNames.begin(), vAllNames.end()); }//end option C else if ((sQuit == "A")||(sQuit == "a")) { vectorvAllNames2; string sName; string sOutAlpha; //load vector with all names: cout << "Enter name of file to sort entries in." << endl; cout << "(I will add the .txt suffix.)" << endl; cin >> sName; sOutAlpha = sName; sName = sName + ".txt"; ifstream finA(sName); if(!finA) cout << "can't find file " << sName << endl; else { while(finA >> sName) { vAllNames2.push_back(sName); } finA.close(); cout << endl; } sort(vAllNames2.begin(), vAllNames2.end()); sOutAlpha = sOutAlpha + "_a.txt"; ofstream foutA(sOutAlpha); if(!foutA) { cout << "can't make file " << sOutAlpha << endl; cout << "Shutting down..." << endl; Sleep(2000); return 0; } for(int r = 0; r < vAllNames2.size(); r++) { foutA << vAllNames2[r] << endl; } cout << "Sorted! See file: " << sOutAlpha << endl; cout << endl; //clean-up: vAllNames2.erase(vAllNames2.begin(), vAllNames2.end()); }//end option A else if ((sQuit == "E")||(sQuit == "e")) { string sOrdet; string sOutFile; vectorvXAllNames; vectorvXtracted; vectorvDirtyChars; char cDirt; string sChecks; char cKolla; //load vector with all text: cout << "Extract e-mail-addresses from a text." << endl; cout << "Enter name of text file to extract from:" << endl; cout << "(I will add the .txt suffix)" << endl; cin >> sOrdet; sOutFile = sOrdet; sOrdet = sOrdet + ".txt"; ifstream fin_X(sOrdet); if(!fin_X) { cout << "can't find file " << sOrdet << endl; cout << "Exiting..." << endl; Sleep(2000); return 0; } while(fin_X >> cDirt) { vDirtyChars.push_back(cDirt); } fin_X.close(); cout << endl; //first add newline instead of , signs so should work w EPIC export text file: ofstream foutClean("cleanfile.txt"); if(!foutClean) { cout << "can't write cleanfile " << endl; cout << "Exiting..." << endl; Sleep(2000); return 0; } for(int d = 0; d < vDirtyChars.size(); d++) { cDirt = vDirtyChars[d]; if((cDirt == ',')||(cDirt == '<')||(cDirt == '>')||(cDirt == '(')||(cDirt == ')')) foutClean << endl; else foutClean << vDirtyChars[d]; } foutClean.close(); //read back cleaned file as string vector: ifstream fin_XC("cleanfile.txt"); if(!fin_XC) { cout << "can't find cleanfile " << endl; cout << "Exiting..." << endl; Sleep(2000); return 0; } while(fin_XC >> sOrdet) { vXAllNames.push_back(sOrdet); } fin_XC.close(); cout << endl; remove("cleanfile.txt"); //Loop through strings, only keep those that contain "@": for(int i = 0; i < vXAllNames.size(); i++) { sChecks = vXAllNames[i]; for(int j = 0; j < sChecks.length(); j++) { cKolla = sChecks.at(j); if (cKolla == '@') vXtracted.push_back(sChecks); } } //print extracted e-mail addresees to file: sOutFile = sOutFile + "EPX" + ".txt"; ofstream foutX(sOutFile); if(!foutX) { cout << "can't make file " << sOutFile << endl; cout << "Exiting..." << endl; Sleep(2000); return 0; } else { for(int m = 0; m < vXtracted.size(); m++) { foutX << vXtracted[m] << endl; } foutX.close(); cout << "Done, results in: " << sOutFile << endl; Sleep(3000); } //clean-up: vXAllNames.erase(vXAllNames.begin(), vXAllNames.end()); vXtracted.erase(vXtracted.begin(), vXtracted.end()); vDirtyChars.erase(vDirtyChars.begin(), vDirtyChars.end()); }//end option E else if ((sQuit == "D")||(sQuit == "d")) { vectorvEmail_addresses; string sFilenameA; string sFilenameB; string sEmail; cout << "Sorts e-mail addresses based on dept." << endl; cout << "(Enter the name of the text file." << endl; cout << "(I will add the .txt suffix in names)." << endl; //load vector with all names: cin >> sFilenameA; sFilenameB = sFilenameA; sFilenameA = sFilenameA + ".txt"; ifstream fin_Ax(sFilenameA); if(!fin_Ax) { cout << "can't find file " << sFilenameA << endl; cout << "Exiting..." << endl; Sleep(2000); return 0; } else { while(fin_Ax >> sEmail) { vEmail_addresses.push_back(sEmail); } fin_Ax.close(); cout << endl; } // sorts on substring after @, usually the department name: sort(vEmail_addresses.begin(), vEmail_addresses.end(), [](const string& a, const string& b) { size_t a_start = a.find_first_of("@"); size_t b_start = b.find_first_of("@"); string a_substring = a.substr(a_start + 1); string b_substring = b.substr(b_start + 1); return a_substring < b_substring; }); //to new output file here: sFilenameB = sFilenameB + "DEPT" + ".txt"; ofstream foutBx(sFilenameB); if(!foutBx) { cout << "cannot write output file" << sFilenameB <vEmails; string sInput; vector vFullnames; string email; string name; string delimiterAT = "@"; string sFullname; string sFirstname; string sLastname; string sTemp; //inport emails to vector from text file: cout << "Extracting 'Name Lastname' from e-mail address." << endl; cout << "Enter name of list." << endl; cout << "I will add the .txt suffix." << endl; cin >> sInput; if(!cin) {cout << "bad first cin" << endl; Sleep(3000); return(0);} string sOutNames = sInput; sInput = sInput + ".txt"; ifstream fin_Ae(sInput); if(!fin_Ae) { cout << "can't find file " << sInput << endl; cout << "Exiting..." << endl; Sleep(2000); return 0; } string sOrd; while(fin_Ae >> sOrd) { vEmails.push_back(sOrd); } fin_Ae.close(); cout << endl; char cX = '.'; int iFirst = 0; string sChecks; char cKolla; int iTestDot = 0; //test for name@domain.com e-mails, abort if present: string sFullnameT; for (int m = 0; m < vEmails.size(); m++) { email = vEmails[m]; sFullnameT = email.substr(0, email.find(delimiterAT)); //extracts full.name for(int j = 0; j < sFullnameT.length(); j++) { cKolla = sFullnameT.at(j); if (cKolla == '.') iTestDot++; } }//end for m test if(vEmails.size() > iTestDot) { cout << "list in " << sInput << " contains an address of type name@domain.com" << endl; cout <<"That will not work for this N function, exiting..." << endl; cout << "iTestDot: " << iTestDot << "vEmails.size(): " << vEmails.size() << endl; // 1 vs 4 ??? Sleep(10000); return(0); } for (int i = 0; i < vEmails.size(); i++) { email = vEmails[i]; sTemp = vEmails[i]; sFullname = email.substr(0, email.find(delimiterAT)); //extracts full.name sFirstname = sFullname; sLastname = sFullname; string sOrigFullname = sFullname; sFirstname.erase(sFirstname.find(cX)); // Trim from and including . to the end of the string //get size of first name, as int, replace those ints in full name = last name iFirst = sFirstname.length(); sFullname.erase(find(sFullname.begin(), sFullname.end(), '.')); //erase . sFullname.replace(sFullname.begin(),sFullname.begin()+ iFirst, "."); //replace first name of full name with . sFullname.erase(find(sFullname.begin(), sFullname.end(), '.')); //erase . sLastname = sFullname; sFirstname = fUpperN(sFirstname); //changed first letter to upper case sLastname = fUpperN(sLastname); //changed first letter to upper case //re-define Full name: sFullname = sFirstname + "%" + sLastname; vFullnames.push_back(sFullname); //stores them, separated by % and with upper case first letters of both names //don't want two vectors here, in case some use single name e-mails... } // Sort the names and last names: sort(vFullnames.begin(), vFullnames.end()); sOutNames = sOutNames + "_N.txt"; string sFirst; string sLast; string sLetter; ofstream foutAn(sOutNames); if(!foutAn) { cout << "can't write file " << sOutNames << endl; cout << "Exiting..." << endl; Sleep(2000); return 0; } else { for(int j = 0; j < vFullnames.size(); j++) { sFullname = vFullnames[j]; //split apart again and print with space separation instead of %: sFirstname = sFullname; sLastname = sFullname; sFirstname.erase(sFirstname.find('%')); // Trim from and including % to the end of the string //get size of first name, as int, replace those ints in full name = last name iFirst = sFirstname.length() + 1; //+ 1 to also catch the % sFullname.replace(sFullname.begin(),sFullname.begin()+ iFirst, "."); //replace first name of full name with . sFullname.erase(find(sFullname.begin(), sFullname.end(), '.')); //erase . sLastname = sFullname; foutAn << sFirstname << " " << sLastname << endl; } } foutAn.close(); cout << endl; cout << "Done! Names are in:" << sOutNames << endl; cout << endl; //clean-up: vEmails.erase(vEmails.begin(), vEmails.end()); vFullnames.erase(vFullnames.begin(), vFullnames.end()); }//end option N else { cout << " You only have options L, S, J, C, A, D, E, H, N, Q..." << endl; cout << endl; } }//end while 1 return 0; }//end main //fCaser: //Reads string passed in, //return lower case string: string fCaser(string S) { string sCleaned; char cInspCase; //safeguard: if(S.size() < 1) { cout << "bad string in fCaser, closing..." << endl; Sleep(3000); return(0);} for(int i = 0; i < S.length(); i++) { cInspCase = S.at(i); switch(cInspCase) { case 'A': { S.replace(i, 1, "a"); } break; case 'B': { S.replace(i, 1, "b"); } break; case 'C': { S.replace(i, 1, "c"); } break; case 'D': { S.replace(i, 1, "d"); } break; case 'E': { S.replace(i, 1, "e"); } break; case 'F': { S.replace(i, 1, "f"); } break; case 'G': { S.replace(i, 1, "g"); } break; case 'H': { S.replace(i, 1, "h"); } break; case 'I': { S.replace(i, 1, "i"); } break; case 'J': { S.replace(i, 1, "j"); } break; case 'K': { S.replace(i, 1, "k"); } break; case 'L': { S.replace(i, 1, "l"); } break; case 'M': { S.replace(i, 1, "m"); } break; case 'N': { S.replace(i, 1, "n"); } break; case 'O': { S.replace(i, 1, "o"); } break; case 'P': { S.replace(i, 1, "p"); } break; case 'Q': { S.replace(i, 1, "q"); } break; case 'R': { S.replace(i, 1, "r"); } break; case 'S': { S.replace(i, 1, "s"); } break; case 'T': { S.replace(i, 1, "t"); } break; case 'U': { S.replace(i, 1, "u"); } break; case 'V': { S.replace(i, 1, "v"); } break; case 'W': { S.replace(i, 1, "w"); } break; case 'X': { S.replace(i, 1, "x"); } break; case 'Y': { S.replace(i, 1, "y"); } break; case 'Z': { S.replace(i, 1, "z"); } break; //case 'Å': { S.replace(i, 1, "å"); } break;//does not work //case 'Ä': { S.replace(i, 1, "ä"); } break; //case 'Ö': { S.replace(i, 1, "ö"); } break; default: { int iBap = 0;} break; //do nothing /* sFullname.replace(sFullname.begin(),sFullname.begin()+ iFirst, "."); //replace first name of full name with . str.replace(str.begin(), str.begin() + 3, 1, 'A'); // (6) */ }//end sw cInspCase }//end for i sCleaned = S; return sCleaned; }//end fCaser string fUpperN(string A) { string B; char cInspect; //safeguard: if(A.size() < 1) { cout << "bad string in fUpper, closing..." << endl; Sleep(3000); return(0);} cInspect = A.at(0); //load first char of string switch(cInspect) { case 'a': { A.replace(0,1,"A"); } break; //replace with upper case, first letter of first name case 'b': { A.replace(0,1,"B"); } break; case 'c': { A.replace(0,1,"C"); } break; case 'd': { A.replace(0,1,"D"); } break; case 'e': { A.replace(0,1,"E"); } break; case 'f': { A.replace(0,1,"F"); } break; case 'g': { A.replace(0,1,"G"); } break; case 'h': { A.replace(0,1,"H"); } break; case 'i': { A.replace(0,1,"I"); } break; case 'j': { A.replace(0,1,"J"); } break; case 'k': { A.replace(0,1,"K"); } break; case 'l': { A.replace(0,1,"L"); } break; case 'm': { A.replace(0,1,"M"); } break; case 'n': { A.replace(0,1,"N"); } break; case 'o': { A.replace(0,1,"O"); } break; case 'p': { A.replace(0,1,"P"); } break; case 'q': { A.replace(0,1,"Q"); } break; case 'r': { A.replace(0,1,"R"); } break; case 's': { A.replace(0,1,"S"); } break; case 't': { A.replace(0,1,"T"); } break; case 'u': { A.replace(0,1,"U"); } break; case 'v': { A.replace(0,1,"V"); } break; case 'w': { A.replace(0,1,"W"); } break; case 'x': { A.replace(0,1,"X"); } break; case 'y': { A.replace(0,1,"Y"); } break; case 'z': { A.replace(0,1,"Z"); } break; default: { int iBip = 0; } break; //do nothing }//end sw cInspect B = A; //duh... return B; }//end fUpperN void setcolor(unsigned int color) { HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(handle, color); }