/////////////////////////////////////////////////////////////////////////////// // // The Soundex Algorithm // // Produces a code for a surname based on the way it sounds // --1st letter of surname is kept (converted to upper case if entered as lower case) // --0 assigned to A, E, I, O, U, H, W, Y // --1 assigned to B, F, P, V // --2 assigned to C, G, J, K, Q, S, X, Z // --3 assigned to D, T // --4 assigned to M, N // --5 assigned to L // --6 assigned to R // // The inputer loops until the sentinel keyboard entry of RETURN us input // // // Paul Yeatman // 20170908 // // Version Notes: // Initial version (v1.0) // some words hang the program "strangebehaviorfollows". "strangebehaviorfo" works, while "strangebehaviorfo" hangs it. "iorfollows" does not hang it. // Vaska produces: VS20 // Laska produces: LS20 // Zelenski produces ZL42 // // The above errors are boggling my mind. Will come back to if feel I need to // /////////////////////////////////////////////////////////////////////////////// #include "console.h" #include "simpio.h" #include "strlib.h" #include using namespace std; /////////////////////////////////////////////////////////////////////////////// // // Constants should be declared here // /////////////////////////////////////////////////////////////////////////////// // replace any instance of chars in assoc string with the stated string const string CONVERT_AEIOUHWY = "0"; const string CONVERT_BFPV = "1"; const string CONVERT_CGJKQSXZ = "2"; const string CONVERT_DT = "3"; const string CONVERT_MN = "4"; const string CONVERT_L = "5"; const string CONVERT_R = "6"; // characters to look for in user entered string const string CONVERT_sAEIOUHWY = "AEIOUHWY"; const string CONVERT_sBFPV = "BFPV"; const string CONVERT_sCGJKQSXZ = "CGJKQSXZ"; const string CONVERT_sDT = "DT"; const string CONVERT_sMN = "MN"; const string CONVERT_sL = "L"; const string CONVERT_sR = "R"; const string CONVERT_s0 = "0"; // for removal of zeros /////////////////////////////////////////////////////////////////////////////// // // Variiables should be declared here // /////////////////////////////////////////////////////////////////////////////// /* !! The convention is supposedly adding an i at the start of ints, d for double, * s for string etc. That causes a lot of work if at some time we want to change * the into to a double and we have placed the variable name iNumber multiple times * in the code with and want to change it to a double. dNumber. We could cast it to * a double, but it would be easier to * not put the lower character i,d etc in front. * * If I want to make the code easier to read, the i, d, s etc is the way to go. */ string sEnteredString = "nothing yet"; string sConvertedString; string sSoundexConversion; string sRepeatsRemoved; string sZerosRemoved; string sSoundexFinalConversion; /////////////////////////////////////////////////////////////////////////////// // // Typedef section. Create an alias name for another data type. // /////////////////////////////////////////////////////////////////////////////// // typedef vector Coordinates; // this gived vector the name of Coordinates. Used for collecting the mouse click points /////////////////////////////////////////////////////////////////////////////// // // Function Prototypes are declare here here, alternately, just whack all the // methods main calls before main! // // Practically, it's good to list them all at the top, so you do not have to work // out where to place it in the list of functions that are written in the program. // Alternately, put the FP's after Main. // /////////////////////////////////////////////////////////////////////////////// void ProgramPurpose(); string CollectNames (); string ConvertNameToCode (string sUppercaseStringConversion); string RemoveRepeats (string sSoundexConversion); string RemoveZeros (string sSoundexConversion); string TruncateOrPadString (string sSoundexConversion); /////////////////////////////////////////////////////////////////////////////// // // DataStructure struct ScoreStats () // // This contains the structure of the data read from he file containing scores // /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // // function ReadFile (string filename) // Usage: ReadFile(the name of the file); // -------------------------------------- // This read a file line by line and calculates some statistics: // min, average and max score. // The calcs are done in memory. // // The scores in the file range from 0 to 100. // /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // // function DisplayStats () // Usage: DisplayStats(); // -------------------------------------- // This spits out the values in memory // /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // // Main Program // /////////////////////////////////////////////////////////////////////////////// int main() { // stuff happens ProgramPurpose(); CollectNames(); return 0; } /////////////////////////////////////////////////////////////////////////////// // // ConvertUppercase (string enteredString) // Converts the passed string into all upper case // /////////////////////////////////////////////////////////////////////////////// void ProgramPurpose(){ // check that Stanford does not have this inbuilt cout << "This program converts the entered surname into a Soundex code.\n"; } /////////////////////////////////////////////////////////////////////////////// // // string CollectNames (); //takes the name from the user // /////////////////////////////////////////////////////////////////////////////// string CollectNames (){ // !!! ACCEPTS NUMBERS AND SYMBOLS IN CURRENT FORM PY 20170908 cout << "Enter surname (RETURN to quit): "; // make sure only character are entered sEnteredString = getLine(); // while (enteredString == "") break; or != RETURN??? if (sEnteredString != "") { //cout << sEnteredString << " is what you entered.\n"; sConvertedString = toUpperCase(sEnteredString); ConvertNameToCode(sConvertedString); //cout << "The non truncated Soundex code for " << sConvertedString << " is " << sSoundexConversion << "\n"; RemoveZeros(sSoundexConversion); //cout << "The Soundex code after removing '0's from " << sConvertedString << " is " << sZerosRemoved << "\n"; RemoveRepeats(sZerosRemoved); // zeros more likley so run that before remove repeats //cout << "With repeats removed Soundex code for " << sConvertedString << " is " << sRepeatsRemoved << "\n"; TruncateOrPadString(sRepeatsRemoved); cout << "The Soundex code for " << sConvertedString << " is " << sSoundexFinalConversion << ".\n"; CollectNames(); } else { cout << "You pressed RETURN. Program has ended.\n"; } // need error check here return sEnteredString; } /////////////////////////////////////////////////////////////////////////////// // // ConvertNameToCode (string uppercaseStringConversion) // Replaces the alphabetical chracters with numbers (excluding the first letter) // // // First round of code is messy and repeats a lot. A case/switch statement surely is better // or some loop that assigns a value to the constants a cycles through 7 times // That way "7" could be a CONSTANT // /////////////////////////////////////////////////////////////////////////////// string ConvertNameToCode (string sUppercaseStringConversion){ sSoundexConversion = sUppercaseStringConversion; for (int i = 0; i < sUppercaseStringConversion.length(); i++) { // we want to retain the very first letter of the surname int iPosition = 1; while ((iPosition = sUppercaseStringConversion.find(CONVERT_sAEIOUHWY[i], iPosition)) != string::npos) { sUppercaseStringConversion.replace(iPosition, 1, CONVERT_AEIOUHWY); } } for (int i = 0; i < sUppercaseStringConversion.length(); i++) { int iPosition = 1; while ((iPosition = sUppercaseStringConversion.find(CONVERT_sBFPV[i], iPosition)) != string::npos) { sUppercaseStringConversion.replace(iPosition, 1, CONVERT_BFPV); } } for (int i = 0; i < sUppercaseStringConversion.length(); i++) { int iPosition = 1; while ((iPosition = sUppercaseStringConversion.find(CONVERT_sCGJKQSXZ[i], iPosition)) != string::npos) { sUppercaseStringConversion.replace(iPosition, 1, CONVERT_CGJKQSXZ); } } for (int i = 0; i < sUppercaseStringConversion.length(); i++) { int iPosition = 1; while ((iPosition = sUppercaseStringConversion.find(CONVERT_sDT[i], iPosition)) != string::npos) { sUppercaseStringConversion.replace(iPosition, 1, CONVERT_DT); } } for (int i = 0; i < sUppercaseStringConversion.length(); i++) { int iPosition = 1; while ((iPosition = sUppercaseStringConversion.find(CONVERT_sMN[i], iPosition)) != string::npos) { sUppercaseStringConversion.replace(iPosition, 1, CONVERT_MN); } } for (int i = 0; i < sUppercaseStringConversion.length(); i++) { int iPosition = 1; while ((iPosition = sUppercaseStringConversion.find(CONVERT_L[i], iPosition)) != string::npos) { sUppercaseStringConversion.replace(iPosition, 1, CONVERT_sL); } } for (int i = 0; i < sUppercaseStringConversion.length(); i++) { int iPosition = 1; while ((iPosition = sUppercaseStringConversion.find(CONVERT_sR[i], iPosition)) != string::npos) { sUppercaseStringConversion.replace(iPosition, 1, CONVERT_R); } } sSoundexConversion = sUppercaseStringConversion; return sSoundexConversion; } /////////////////////////////////////////////////////////////////////////////// // // RemoveZeros (string SoundexConversion) // Removes zeros from the passed string so A102030405060 becomes A123456 // /////////////////////////////////////////////////////////////////////////////// string RemoveZeros (string sSoundexConversion){ for (int i = 0; i < sSoundexConversion.length(); i++) { // we want to retain the very first letter of the surname int iPosition = 0; while ((iPosition = sSoundexConversion.find(CONVERT_s0[i], iPosition)) != string::npos) { sSoundexConversion.replace(iPosition, 1, ""); } } sZerosRemoved = sSoundexConversion; return sZerosRemoved; // according to lecure 3 the following code would do it /* int found; while ((found = sSoundexConversion.find(CONVERT_s0)) != string::npos) sSoundexConversion.erase(pos, 1); // pos not declared in scope so missing a lib no doubt return sZerosRemoved; // */ } /////////////////////////////////////////////////////////////////////////////// // // RemoveRepeats (string SoundexConversion) // Removes repeated characters, so A11111111222222223333333456 becomes A123456 // // A loop is in place to make sure ALL repeats are removed. // /////////////////////////////////////////////////////////////////////////////// string RemoveRepeats (string sSoundexConversion){ for (int i = 1; i < sSoundexConversion.length(); i++) { // we want to retain the very first letter of the surname int tracker = 1; while (tracker > 0) { int iPosition = 0; if (sSoundexConversion[i] == sSoundexConversion[i+1]) { sSoundexConversion.replace(i, 1, ""); tracker = 1; } else tracker = 0; } } sRepeatsRemoved = sSoundexConversion; return sRepeatsRemoved; } /////////////////////////////////////////////////////////////////////////////// // // TruncateOrPadString (string SoundexConversion) // Ensures the final string is 4 characters in length i.e // --A123456 becomes A123 // --A1 becomes A100 // // For a large string, this would be looped rather than explxitly stated // // Another good opportunity to use the switch statement // /////////////////////////////////////////////////////////////////////////////// string TruncateOrPadString (string sRepeatsRemoved){ int x = sRepeatsRemoved.length(); if (x == 1) { sRepeatsRemoved += "000"; } if (x == 2) { sRepeatsRemoved += "00"; } if (x == 3) { sRepeatsRemoved += "0"; } if (x > 4) { // remove additional characters from position x=4 onwards // from http://www.cplusplus.com/reference/string/string/erase/ sRepeatsRemoved.erase (4, string::npos); } else if (x == 4) { //do nothing } sSoundexFinalConversion = sRepeatsRemoved; return sSoundexFinalConversion; }