K
kwikius
John said:bool StrLowCompare( std::string& String1, std::string& String2 )
{
if ( String1.size() != String2.size() )
return false;
for ( std::string::size_type i = 0; i < String1.size(); ++i )
{
if ( tolower( String1 ) != tolower( String2 )
return false;
}
return true;
}
If I had a pound for everytime this mistake is made I would be as rich
as Bill Gates.tolower( String1 )
is undefined since char may be signed and therefore you may pass a
negative number to tolower. tolower is only defined on integer values in
the range of unsigned char and the value of EOF.tolower( (unsigned char) String1 )
is correct.This also means thatstd::transform(str.begin(), str.end(), tolower)is undefined for the same reason.
That wording is a little too harsh. The above code has perfectly
well-defined behavior for quite a lot of input values. To dismiss it as
undefined is like saying *p is undefined since p might be null. I agree,
however, that one can and should do better.
For the use in std::transform(), I would suggest a function object like
this:
<cut, reuseed in following ..>
Can also use accumulate. Needs an iterator to work on the pair of
strings...
I'll leave it to the experts to work out how compliant the following
is;-)
tested in VC7.1 only
regards
Andy Little
#include <locale>
#include <string>
#include <iterator>
#include <utility>
#include <numeric>
//iterator for comapring strings
// Not really sorted what to do on different lengths
// if pos >= shortest
// just compare up to end of shorter here
template <typename Str>
struct string_pair_iterator{
string_pair_iterator(
Str const & c1_in,
Str const & c2_in,
typename Str::size_type pos_in =0
)
:c1(c1_in),c2(c2_in),pos(pos_in)
{
if (pos >= std::min(c1.length(),c2.length())){
pos = Str::npos;
}
}
typedef std:
typename Str::value_type , typename Str::value_type
typedef value_type * pointer;> value_type;
typedef value_type & reference;
typedef std::forward_iterator_tag iterator_category;
bool operator==(string_pair_iterator const & rhs)const
{
return pos == rhs.pos;
}
bool operator!=(string_pair_iterator const & rhs)const
{
return pos != rhs.pos;
}
value_type operator *() const
{
return value_type(c1[pos],c2[pos]);
}
string_pair_iterator const & operator++()
{
if (pos != Str::npos){
++pos;
if (pos >= std::min(c1.length(),c2.length())){
pos = Str::npos;
}
}
return *this;
}
string_pair_iterator operator++(int)
{
string_pair_iterator temp = *this;
if (pos != Str::npos){
++pos;
if (pos >= min(c1.length(),c2.length())){
pos = Str::npos;
}
}
return temp;
}
private:
typename Str::size_type pos;
Str const & c1;
Str const & c2;
};
//comparator
// F is char modifier as
// to_lower from Kai_Uwe Box below...
template <typename Str, typename F>
struct string_pair_cmp{
string_pair_cmp(F const & f_in = F() )
:f(f_in){}
typedef std:
typename Str::value_type , typename Str::value_type
> pair_type;
bool operator()(bool b,pair_type in)
{
if (! b) return false;
return f(in.first)==f(in.second);
}
private:
F f;
};
//courtesy Kai-Uwe Box..
class to_lower {
std::locale const & loc;
public:
to_lower ( std::locale const & r_loc = std::locale() )
: loc ( r_loc )
{}
template < typename CharT >
CharT operator() ( CharT chr ) const {
return( std::tolower( chr, this->loc ) );
}
}; // class to_lower;
#include <iostream>
int main()
{
std::string str1 = "hellO";
std::string str2 = "Hello";
typedef string_pair_iterator<std::string> striter;
bool res1 = std::accumulate(
striter(str1,str2),
striter(str1,str2,std::min(str1.length(),str2.length())),
true,
string_pair_cmp<std::string,to_lower>())
;
std::cout << res1 <<'\n';
std::string str3 = "hell0";
bool res2 = std::accumulate(
striter(str1,str3),
striter(str1,str3,std::min(str1.length(),str3.length())),
true,
string_pair_cmp<std::string,to_lower>())
;
std::cout << res2 <<'\n';
}