Archived

This topic is now archived and is closed to further replies.

daerid

std::string case insensitive comparison

Recommended Posts

daerid    354
Apparently using operator== does a case-sensitive compare. I was wondering if there was an easier way than doing:
stricmp(string.c_str(),"somestring");
 

Share this post


Link to post
Share on other sites
Oluseyi    2115
std::string temp = "SomeThIng";
std::transform( temp.begin(), temp.end(), temp.begin(), temp.end(), tolower );
if( temp == str )
// yadda


[ GDNet Start Here | GDNet Search Tool | GDNet FAQ ]
[ MS RTFM [MSDN] | SGI STL Docs | Boost ]
[ Google! | Asking Smart Questions | Jargon File ]
Thanks to Kylotan for the idea!

Share this post


Link to post
Share on other sites
Fruny    1658
There are ways, but you will get into trouble with locales anyways (i.e. what is the meaning of ''case'')

You can use lexicographical_compare and give it your own comparison operator.


  
#include <algorithm>
using std::lexicographical_compare;

bool CaseInsensitiveLess( const char& c1, const char& c2 )
{
return tolower(c1)<tolower(c2);
}

lexicographical_compare( str1.begin(), str1.end(), str2.begin(), str2.end(), CaseInsensitiveLess );


Or, for better efficiency, define your comparison as a functor


  
struct CaseInsensitiveLess
{
inline bool operator()( const char& c1, const char& c2 ) const
{
return tolower(c1)<tolower(c2);
}
};

lexicographical_compare( str1.begin(), str1.end(), str2.begin(), str2.end(), CaseInsensitiveLess() );
// note the presence of parentheses, we are creating a temporary object by calling the constructor for CaseInsensitiveLess




Assuming tolower() is inlined too, that should go well.

[Questions (STFW) | GDNet Start Here | GDNet Search | Forum FAQ | Google | Asking Smart Questions ]
[Docs (RTFM) | MSDN | SGI''s STL | OpenGL | File formats]
[C++ Must Haves (RTFS) | MinGW | Boost | Loki | FLTK | SDL ]

Stolen from Magmai Kai Holmlor, who held it from Oluseyi, who was inspired by Kylotan...

Share this post


Link to post
Share on other sites
Xai    1848
The last post has it exactly right .. EXCEPT ...i don''t understand why you say ... to make it more efficient ... use a function ...

I assume you are saying that, because you know how to inline a member function .. but you can inline ANY function ... that is the point. An inline functor member will be less efficient than a normal function ... because it is not static ... and therefore might pass a "this" pointer to the function (compiler optimization not considered), even though there is no member data to care about.

So write a normal inline function ... and pass it to lexigraphicalcompare

Good Luck

Share this post


Link to post
Share on other sites
Fruny    1658
But an inlined function has, by definition, no address.
Therefore, if you take the address of the function and pass it to lexicographical_compare, it will not be inlined.

static or not, since the functor operator() call is inlined, the *this pointer will never be passed... because there is no function call in the first place.

[Questions (STFW) | GDNet Start Here | GDNet Search | Forum FAQ | Google | Asking Smart Questions ]
[Docs (RTFM) | MSDN | SGI's STL | OpenGL | File formats]
[C++ Must Haves (RTFS) | MinGW | Boost | Loki | FLTK | SDL ]

Stolen from Magmai Kai Holmlor, who held it from Oluseyi, who was inspired by Kylotan...


[edited by - Fruny on April 30, 2002 4:22:20 PM]

Share this post


Link to post
Share on other sites
DrPizza    160

  
template <typename T>
struct ci_char_traits :
public std::char_traits<T>
{
static bool eq(const T& lhs, const T& rhs)
{
return tolower(lhs) == tolower(rhs);
}
static bool ne(const T& lhs, const T& rhs)
{
return tolower(lhs) != tolower(rhs);
}
static bool lt(const T& lhs, const T& rhs)
{
return tolower(lhs) < tolower(rhs);
}
static int compare(const T* s1, const T* s2, size_t n)
{
return memicmp((void*)s1, (void*)s2, n * sizeof(T));
}
static const T* find(const T* str, size_t count, const T& ch)
{
for(size_t i = 0; i < count; ++i)
{
if(utility::ci_char_traits<T>::eq(str[i], ch))
{
return str + i;
}
}
return NULL;
}
};

typedef std::basic_string<char, ci_char_traits<char> > ci_string;
typedef std::basic_string<wchar_t, ci_char_traits<wchar_t> > wci_string;


ci_strings will then be case-insensitively compared; they could be easily altered to take a locale. There are some issues; the various iostream overloads [annoyingly and as far as I can tell unnecessarily] assume that the traits of the string are the same as the traits of the stream, but it works well enough. And for things like Win32, which are generally case insensitive (for things like filenames and extensions, registry keys, and so on), it can save a lot of calls to nasty C-string functions.


Share this post


Link to post
Share on other sites
daerid    354
DrPizza, our resident forum template fanatic :D

I love you, man. that's exactly what I was looking for.


[edited by - daerid on May 1, 2002 1:27:33 PM]

Share this post


Link to post
Share on other sites