Thread: Making a vector<string> case insensitive

  1. #1
    Registered User
    Join Date
    Mar 2016
    Posts
    203

    Making a vector<string> case insensitive

    I have a vector<string> that I'd like to make case insensitive i.e.
    (a) strings that always appear with first character upper-case, like proper nouns, should remain unchanged but,
    (b) if a string appears with upper case first character that when replaced with a lower case of the same character has another matching string in the vector, then the lower case first character version of the string should be retained.


    So, in short, if my vector<string> is ...
    Code:
         {"at", "Google", "At", "holiday", "Google", "experiment"}
    ... the program output should be:
    Code:
       {"at", "Google", "at", "holiday", "Google", "experiment"} //Assume string.length() > 1, for now, for all strings;

    My psuedo-code for this runs on the following lines - for each vector element:
    1. check if element[0] is uppercase; if not uppercase then continue to next vector element;
    2. if element[0] is uppercase, convert this element[0] to lowercase and add to it the remaining sub-string - assign this to the original element and check if there is any match of this modified vector element with any other vector elements
    3. if no match, convert element[0] back to upper case, add to it the remaining sub-string, this is now the new new vector element which is == the original vector element and move to next vector element
    4. if match, move to next vector element


    Based on the above lines of thinking, my program is as follows:
    Code:
    #include<iostream>
    #include<vector>
    #include<locale>
    #include<algorithm>
    #include<string>
    
    
    using namespace std;
    
    
    int main(){
      vector<string> v {"at", "Google", "At", "holiday", "Google", "experiment"};
      for(auto& itr:v){
        if( (isupper(itr[0])) != 0){
           itr = tolower(itr[0], locale()) + itr.substr(1);
                if(!(find(v.begin(), v.end(), itr) != v.end())){
                itr = toupper(itr[0], locale())+itr.substr(1);
                }
            }
        }
      for(auto& itr: v){
        cout<<itr<<"\n";
      }
    }

    However, the program output is:
    Code:
       {"at", "google", "at", "holiday", "google", "experiment"}
    Could someone please let me know where exactly might be the problem in the psuedo and/or actual code? Many thanks!

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    It seems to me that the problem lies here:
    Code:
    itr = tolower(itr[0], locale()) + itr.substr(1);
    You have specified that itr is a reference to the current element of the vector, and here you change it. Therefore, the element in the vector is changed, so when you search the vector, of course you find the changed element and hence you retain it.

    I would suggest:
    Code:
    #include<iostream>
    #include<vector>
    #include<locale>
    #include<algorithm>
    #include<string>
    
    using namespace std;
      
    int main()
    {
        vector<string> words{"at", "Google", "At", "holiday", "Google", "experiment"};
        for (auto& word : words)
        {
            if (isupper(word[0]))
            {
                auto lowercase_initial_word = tolower(word[0], locale()) + word.substr(1);
                if (find(words.begin(), words.end(), lowercase_initial_word) != words.end())
                {
                    word = lowercase_initial_word;
                }
            }
        }
    
        for (auto& word : words)
        {
            cout << word << "\n";
        }
    }
    EDIT:
    Alternatively, instead of assigning the entire lowercase_initial_word to word, perhaps it would be better to write:
    Code:
    auto lowercase_initial = tolower(word[0], locale());
    auto lowercase_initial_word = lowercase_initial + word.substr(1);
    if (find(words.begin(), words.end(), lowercase_initial_word) != words.end())
    {
        word[0] = lowercase_initial;
    }
    Also, the assumption is that the words are not empty. This holds true in the test input, but it is a bad habit to rely on the input being correct in format. For correctness, you should check for that, i.e., change:
    Code:
    if (isupper(word[0]))
    to:
    Code:
    if (!word.empty() && isupper(word[0]))
    Last edited by laserlight; 10-27-2016 at 12:26 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Mar 2016
    Posts
    203
    @laserlight: many thanks for, yet another, astute diagnosis and helpful suggestion.

    My follow-on question in this case would be what is the best way to check whether a particular element in a vector (or more generally, STL container) has any other matches within the same vector (container)?

  4. #4
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Code:
    container<value_type>::iterator found = std::find(container.begin(), container.end(), what);
    while (found != container.end()) {
       found = std::find(found + 1, container.end(), what);
    }

  5. #5
    Registered User
    Join Date
    Mar 2016
    Posts
    203
    Useful to know, thanks

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Sorting a string, case insensitive
    By kasprzap in forum C Programming
    Replies: 1
    Last Post: 01-14-2010, 05:04 PM
  2. case insensitive string comparison
    By osiris07 in forum C Programming
    Replies: 9
    Last Post: 04-20-2009, 05:41 PM
  3. Case insensitive string compare...?
    By cpjust in forum C++ Programming
    Replies: 9
    Last Post: 02-22-2008, 04:44 PM
  4. wildcard case insensitive string compare
    By lawina in forum C Programming
    Replies: 3
    Last Post: 06-13-2006, 03:27 AM
  5. Making a CString map case insensitive
    By tygernoot in forum C++ Programming
    Replies: 4
    Last Post: 06-20-2005, 01:01 PM

Tags for this Thread