Mark
Mark

Reputation: 6321

String comparisons. How can you compare string with std::wstring? WRT strcmp

I am trying to compare two formats that I expected would be somewhat compatible, since they are both generally strings. I have tried to perform strcmp with a string and std::wstring, and as I'm sure C++ gurus know, this will simply not compile. Is it possible to compare these two types? Is there an easy conversion here?

Upvotes: 7

Views: 14580

Answers (4)

Pavel Minaev
Pavel Minaev

Reputation: 101595

You need to convert your char* string - "multibyte" in ISO C parlance - to a wchar_t* string - "wide character" in ISO C parlance. The standard function that does that is called mbstowcs ("Multi-Byte String To Wide Character String")

NOTE: as Steve pointed out in comments, this is a C99 function and thus is not ISO C++ conformant, but may be supported by C++ implementations as an extension. MSVC and g++ both support it.

It is used thus:

const char* input = ...;

std::size_t output_size = std::mbstowcs(NULL, input, 0); // get length
std::vector<wchar_t> output_buffer(output_size);

// output_size is guaranteed to be >0 because of \0 at end
std::mbstowcs(&output_buffer[0], input, output_size);

std::wstring output(&output_buffer[0]);

Once you have two wstrings, just compare as usual. Note that this will use the current system locale for conversion (i.e. on Windows this will be the current "ANSI" codepage) - normally this is just what you want, but occasionally you'll need to deal with a specific encoding, in which case the above won't do, and you'll need to use something like iconv.

EDIT

All other answers seem to go for direct codepoint translation (i.e. the equivalent of (wchar_t)c for every char c in the string). This may not work for all locales, but it will work if e.g. your char are all ASCII or Latin-1, and your wchar_t are Unicode. If you're sure that's what you really want, the fastest way is actually to avoid conversion altogether, and to use std::lexicographical_compare:

#include <algorithm>

const char* s = ...;
std::wstring ws = ...;

const char* s_end = s + strlen(s);

bool is_ws_less_than_s = std::lexicographical_compare(ws.begin, ws.end(),
                                                      s, s_end());
bool is_s_less_than_ws = std::lexicographical_compare(s, s_end(),
                                                      ws.begin(), ws.end());
bool is_s_equal_to_ws = !is_ws_less_than_s && !is_s_less_than_ws;

If you specifically need to test for equality, use std::equal with a length check:

#include <algorithm>

const char* s = ...;
std::wstring ws = ...;

std::size_t s_len = strlen(s);
bool are_equal =
    ws.length() == s_len &&
    std::equal(ws.begin(), ws.end(), s);

Upvotes: 11

Jacob
Jacob

Reputation: 34601

Convert your wstring to a string.

wstring a = L"foobar";
string  b(a.begin(),a.end());

Now you can compare it to any char* using b.c_str() or whatever you like.

char c[] = "foobar";
cout<<strcmp(b.c_str(),c)<<endl;

Upvotes: 2

Ryu
Ryu

Reputation: 8749

First of all you have to ask yourself why you are using std::wstring which is a unicode format with char* (cstring) which is ansi. It is best practice to use unicode because it allows your application to be internationalized, but using a mix doesn't make much sense in most cases. If you want your cstrings to be unicode use wchar_t. If you want your STL strings to be ansi use std::string.

Now back to your question.

The first thing you want to do is convert one of them to match the other datatype.

std::string an std::wstring have the c_str function

here are the function definitions

const char* std::string::c_str() const
const wchar_t* std::wstring::c_str() const

I don't remember off hand how to convert char * to wchar_t * and vice versa, but after you do that you can use strcmp. If you google you'll find a way.

You could use the functions below to convert std::wstring to std::string then c_str will give you char * which you can strcmp

#include <string>
#include <algorithm>

// Prototype for conversion functions
std::wstring StringToWString(const std::string& s);
std::string WStringToString(const std::wstring& s);

std::wstring StringToWString(const std::string& s)
{
std::wstring temp(s.length(),L' ');
std::copy(s.begin(), s.end(), temp.begin());
return temp; 
}


std::string WStringToString(const std::wstring& s)
{
std::string temp(s.length(), ' ');
std::copy(s.begin(), s.end(), temp.begin());
return temp; 
}

Upvotes: 2

Tom Leys
Tom Leys

Reputation: 19029

The quick and dirty way is

if( std::wstring(your_char_ptr_string) == your_wstring)

I say dirty because it will create a temporary string and copy your_char into it. However, it will work just fine as long as you are not in a tight loop.

Note that wstring uses 16 bit characters (i.e unicode - 65536 possible characters) whereas char* tends to be 8 bit characters (Ascii, Latin english only). They are not the same, so wstring-->char* might loose accuracy.

-Tom

Upvotes: 2

Related Questions