Thread: Find whole word in string, case insensetive.

  1. #1
    Registered User
    Join Date
    Sep 2007
    Posts
    29

    Find whole word in string, case insensetive.

    im trying find a word in a string but Mach the whole word only ( ex. "pan" should not Mach "expansive" but should Mach "PAN" ). heres what i have so far:

    Code:
    bool ci_equal(const char ch1, const char ch2)
    {
        return toupper((unsigned char)ch1) == toupper((unsigned char)ch2);
    }
    
    size_t ci_find(const std::string& str1, const std::string& str2)
    {
        std::string::const_iterator pos = search(str1. begin ( ), str1. end ( ), str2.begin ( ), str2. end ( ), ci_equal);
        if (pos == str1. end ( ))
        return std::string::npos;
        else
        return pos - str1. begin ( );
    }
    
    size_t ci_find_word(const std::string& str1, const std::string& str2)
    {
        std::string::const_iterator pos = search(str1. begin ( ), str1. end ( ), str2.begin ( ), str2. end ( ), ci_equal);
        if ( pos != str1.end() && ( pos == str1.begin() || str1.at(pos-str1.begin()-1 ) == ' ') && ( pos == str1.end() || str1.at((pos-str1.begin())+str2.size()-1 ) == ' ') ) return pos - str1. begin ( );
        else return std::string::npos;
    }
    ci_find works fine but ci_find_word always returns std::string::npos. excuse my ignorance but why do const_iterator, size_ts even exist? couldn't it be done with ints? they are a pain. they have been hell to deal with.

  2. #2
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    So have you done any debugging? Call it with something you know will match, and have your function print out your conditions (true/false), the value of pos-str1.begin(), etc.

    Also, this:
    Code:
    pos == str1.end()
    probably isn't right, since you want to check pos+str2.length().

  3. #3
    Registered User
    Join Date
    Oct 2008
    Posts
    1,262
    Addition to tabstop (he beat me to it)...

    This:
    Code:
    str1.at(pos-str1.begin()-1 ) == ' '
    Should probably be
    Code:
    str1.at(pos-1 ) == ' '

  4. #4
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by EVOEx View Post
    Addition to tabstop (he beat me to it)...

    This:
    Code:
    str1.at(pos-str1.begin()-1 ) == ' '
    Should probably be
    Code:
    str1.at(pos-1 ) == ' '
    I don't think you can throw a const_iterator into at; instead you turn it into a number first (which is what he has done).

  5. #5
    Registered User
    Join Date
    Oct 2008
    Posts
    1,262
    Quote Originally Posted by tabstop View Post
    I don't think you can throw a const_iterator into at; instead you turn it into a number first (which is what he has done).
    Ahhh.. pos is an iterator... I missed that. So wouldn't *(pos - 1) work?
    I'm not sure if the standard defines the operator- though, on an iterator of a string... So someone should verify.

  6. #6
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    For a string, your standard iterators are bidirectional, so - would work. I can't think of a reason (other than paranoia) why *(pos - 1) wouldn't work (it would be a problem if pos was at the beginning of the string, but the short-circuit || should prevent that from happening.

  7. #7
    Registered User
    Join Date
    Sep 2007
    Posts
    29
    small debug program:

    Code:
    bool ci_equal(const char ch1, const char ch2)
    {
        return toupper((unsigned char)ch1) == toupper((unsigned char)ch2);
    }
    
    size_t ci_find(const std::string& str1, const std::string& str2)
    {
        std::string::const_iterator pos = search(str1. begin ( ), str1. end ( ), str2.begin ( ), str2. end ( ), ci_equal);
        if (pos == str1. end ( ))
        return std::string::npos;
        else
        return pos - str1. begin ( );
    }
    
    size_t ci_find_word(const std::string& str1, const std::string& str2)
    {
        std::string::const_iterator pos = search(str1. begin ( ), str1. end ( ), str2.begin ( ), str2. end ( ), ci_equal);
        std::cout<<"pos = "<<pos-str1.begin()<<std::endl;
        if ( pos != str1.end() && ( pos == str1.begin() || str1.at(pos-str1.begin()-1 ) == ' ') && ( pos+str2.length() == str1.end() || str1.at((pos-str1.begin())+str2.size()-1 ) == ' ') ) return pos - str1. begin ( );
        else return std::string::npos;
    }
    
    void cd_to_exe_dir( char *argv[] )
    {
        std::string path = argv[0];
        int ii = path.length();
        while ( !( path[ii] == '/' || path[ii] == '\\' ) ) ii--;
        path.erase( ii, 100 );
        chdir( path.c_str() );
    }
    
    int main( int argc, char *argv[] )
    {
        cd_to_exe_dir( argv );
        std::string searchword = "fox";
        std::string searchin   = "this is fierfox 4.0";
        std::string searchin2   = "there is a Fox in here";
        if ( ci_find_word( searchword, searchin ) != std::string::npos ) std::cout<<"found \""<<searchword<<"\" in \""<<searchin<<"\"\n";
        else std::cout<<"did not find \""<<searchword<<"\" in \""<<searchin<<"\"\n";
        if ( ci_find_word( searchword, searchin2 ) != std::string::npos ) std::cout<<"found \""<<searchword<<"\" in \""<<searchin2<<"\"\n";
        else std::cout<<"did not find \""<<searchword<<"\" in \""<<searchin2<<"\"\n";
        return(0);
    }
    output:

    Code:
    pos = 3
    did not find "fox" in "this is fierfox 4.0"
    pos = 3
    did not find "fox" in "there is a Fox in here"
    
    Press ENTER to continue.
    Im still wondering, why where iterators included in the standard?
    Last edited by IM back!; 03-18-2010 at 12:49 PM.

  8. #8
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Why are iterators included? Because you need things to walk through container objects (and the C++ STL is all about the container object). You need something that's going to walk through a map, and a list, and even a string. What else are you going to use? (The idea is that, for instance, pointers (in an array, for instance) are iterators, in every sense of the term. Iterators extend that concept (but don't necessarily use the same implementation).

    You do realize you're searching for "this is fierfox 4.0" inside the string "fox" and not the other way around? (str1 is your container, str2 is what is searched for.)

  9. #9
    Registered User
    Join Date
    Sep 2007
    Posts
    29
    Quote Originally Posted by tabstop View Post
    Why are iterators included? Because you need things to walk through container objects (and the C++ STL is all about the container object). You need something that's going to walk through a map, and a list, and even a string. What else are you going to use? (The idea is that, for instance, pointers (in an array, for instance) are iterators, in every sense of the term. Iterators extend that concept (but don't necessarily use the same implementation).
    why not use ints?

    Quote Originally Posted by tabstop View Post
    You do realize you're searching for "this is fierfox 4.0" inside the string "fox" and not the other way around? (str1 is your container, str2 is what is searched for.)
    thanks for caching that:

    still dosent work tho heres the new output:

    Code:
    pos = 12
    did not find "fox" in "this is fierfox 4.0"
    pos = 11
    did not find "fox" in "there is a Fox in here"
    
    Press ENTER to continue.

  10. #10
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by IM back! View Post
    why not use ints?
    Because ints are nowhere near up to the task? Ints can handle arrays just fine; but anything more complicated (even a plain vanilla linked list, like you would code yourself) and your ints will fold like a cheap suit.
    Quote Originally Posted by IM back! View Post
    thanks for caching that:

    still dosent work tho heres the new output:

    Code:
    pos = 12
    did not find "fox" in "this is fierfox 4.0"
    pos = 11
    did not find "fox" in "there is a Fox in here"
    
    Press ENTER to continue.
    And also you need to look after your word for the ending space, not before the last the letter of the word.

  11. #11
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by tabstop
    For a string, your standard iterators are bidirectional, so - would work.
    A slight correction: the iterators of std::string are random access iterators, for which operator- is defined. Bidirectional iterators do not necessarily provide operator-, thus if you want to be more general you should use std::distance().
    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

  12. #12
    Registered User
    Join Date
    Sep 2007
    Posts
    29
    thanks, still no good tho

    Code:
    bool ci_equal(const char ch1, const char ch2)
    {
        return toupper((unsigned char)ch1) == toupper((unsigned char)ch2);
    }
    
    size_t ci_find(const std::string& str1, const std::string& str2)
    {
        std::string::const_iterator pos = search(str1. begin ( ), str1. end ( ), str2.begin ( ), str2. end ( ), ci_equal);
        if (pos == str1. end ( ))
        return std::string::npos;
        else
        return pos - str1. begin ( );
    }
    
    size_t ci_find_word(const std::string& str1, const std::string& str2)
    {
        std::string::const_iterator pos = search(str1. begin ( ), str1. end ( ), str2.begin ( ), str2. end ( ), ci_equal);
        std::cout<<"pos = "<<pos-str1.begin()<<std::endl;
        if ( pos != str1.end() && ( pos == str1.begin() || str1.at(pos-str1.begin()-1 ) == ' ') && ( pos+str2.length() == str1.end() || str1.at((pos-str1.begin())+str2.size()+1 ) == ' ') ) return pos - str1. begin ( );
        else return std::string::npos;
    }

  13. #13
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Checking the letter after where you want the space to be also won't help much, either.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 5
    Last Post: 03-05-2009, 11:32 AM
  2. OOP Question DB Access Wrapper Classes
    By digioz in forum C# Programming
    Replies: 2
    Last Post: 09-07-2008, 04:30 PM
  3. Replies: 8
    Last Post: 04-25-2008, 02:45 PM
  4. Replies: 4
    Last Post: 03-03-2006, 02:11 AM
  5. opengl program as win API menu item
    By SAMSAM in forum Game Programming
    Replies: 1
    Last Post: 03-03-2003, 07:48 PM