#include <string>
#include <iostream>
#include <cctype>

// case insensitive character traits
// inherited copy (preserves case),
// case insensitive comparison, search
struct traits_nocase : std::char_traits<char>
{
  static bool eq( const char& c1, const char& c2 )
  { return toupper(c1) == toupper(c2) ; }
  static bool lt( const char& c1, const char& c2 )
  { return toupper(c1) < toupper(c2) ; }     
  static int compare( const char* s1, const char* s2, size_t N )
  {
    return strncasecmp( s1, s2, N ) ; // posix
    // mirosoft C++ - use _strnicmp instead
  }
  static const char* find( const char* s, size_t N, const char& a )
  {
    for( size_t i=0 ; i<N ; ++i )
      if( toupper(s[i]) == toupper(a) ) return s+i ;
    return 0 ; 
  }
  static bool eq_int_type ( const int_type& c1, const int_type& c2 )
  { return toupper(c1) == toupper(c2) ; }
};

// string preserves case; comparisons are case insensitive
typedef std::basic_string< char, traits_nocase > string_nocase ;

// make string_nocase work like a std::string 
//           with streams using std::char_traits
// std::basic_istream< char, std::char_traits<char> > (std::istream) and
// std::basic_ostream< char, std::char_traits<char> > (std::ostream)
inline std::ostream& operator<< ( std::ostream& stm, const string_nocase& str )  
{ return stm << reinterpret_cast<const std::string&>(str) ; }

inline std::istream& operator>> ( std::istream& stm, string_nocase& str )  
{ 
  std::string s ; stm >> s ;
  if(stm) str.assign(s.begin(),s.end()) ; 
  return stm ; 
}

inline std::istream& getline( std::istream& stm, string_nocase& str )
{ 
  std::string s ; std::getline(stm,s) ;
  if(stm) str.assign(s.begin(),s.end()) ;
  return stm ; 
}
      
// some examples of using string_nocase
#include <fstream>
#include <iterator>
#include <algorithm>
#include <map>
using namespace std;
      
int main()
{
   string_nocase str1 = "http://www.daniweb.com/forums/forum8.html" ;
   string_nocase str2 = "Http://www.DaniWeb.com/Forums/FORUM8.html" ;
   cout << "str1 == str2 ? " << boolalpha << (str1==str2) << '\n' ;
   
   string_nocase sub_str ; 
   cout << "string to find? " ; getline(cin,sub_str) ;
   if( str1.find( sub_str ) != string_nocase::npos ) 
     cout << "found " << sub_str << " in " << str1 << '\n' ;
   
   ifstream file(__FILE__) ;
   istream_iterator<string_nocase> begin(file), end ; 
   cout << "#includes: " << count( begin, end, "#INCLUDE" ) << '\n' ;
   
   map<string_nocase,int> phone_book ;
   phone_book[ "SALEM" ] = -72 ;
   phone_book[ "~s.o.s~" ] = 1234567 ;
   phone_book[ "salem" ] = 9999999 ;
   cout << phone_book[ "~S.O.S~" ] << '\t' << phone_book[ "SALEM" ] << '\n' ;
}

// what we have done is customize the character traits policy
// std::basic_string is also policy free wrt memory management
// see http://www.ddj.com/dept/cpp/184403784 for some examples of  
// customizing the memory allocator policy.


/**
Output:

> g++ -Wall -std=c++98 string_nocase.cpp && ./a.out
str1 == str2 ? true
string to find? OM/FOR
found OM/FOR in http://www.daniweb.com/forums/forum8.html
#includes: 7
1234567 9999999
*/
2
Contributors
1
Reply
3
Views
10 Years
Discussion Span
Last Post by ~s.o.s~
0

Nice snippet, though it would be better if you included the output so that beginners don't have to compile and execute your code to understand what is going on.

Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.