Start New Discussion within our Software Development Community

a string which can be used ala std::string, preserves case, but comparisons are not case sensitive.

#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
*/

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.

The article starter has earned a lot of community kudos, and such articles offer a bounty for quality replies.