I want to efficiently compare a QString and a std::string for (in)equality. Which is the best way to do it, possibly without creating intermediate objects?
QString::fromStdString() and QString::toStdString() comes to mind, but they create temporary copy of the string, so afaik, if you don't want to have temporary objects, you will have to write this function yourself (though what is more efficient is a question).
Example:
QString string="string";
std::string stdstring="string";
qDebug()<< (string.toStdString()==stdstring); // true
QString string="string";
std::string stdstring="std string";
qDebug()<< (str==QString::fromStdString(stdstring)); // false
By the way in qt5, QString::toStdString() now uses QString::toUtf8() to perform the conversion, so the Unicode properties of the string will not be lost (qt-project.org/doc/qt-5.0/qtcore/qstring.html#toStdString
It can be done without intermediate objects, if you are absolutely sure that the two strings contain only Latin characters:
bool latinCompare(const QString& qstr, const std::string& str)
{
if( qstr.length() != (int)str.size() )
return false;
const QChar* qstrData = qstr.data();
for( int i = 0; i < qstr.length(); ++i ) {
if( qstrData[i].toLatin1() != str[i] )
return false;
}
return true;
}
Otherwise you should decode the std::string into a QString and compare the two QStrings.
Related
What is the most basic way to do it?
If compiled with STL compatibility, QString has a static method to convert a std::string to a QString:
std::string str = "abc";
QString qstr = QString::fromStdString(str);
If by string you mean std::string you can do it with this method:
QString QString::fromStdString(const std::string & str)
std::string str = "Hello world";
QString qstr = QString::fromStdString(str);
If by string you mean Ascii encoded const char * then you can use this method:
QString QString::fromAscii(const char * str, int size = -1)
const char* str = "Hello world";
QString qstr = QString::fromAscii(str);
If you have const char * encoded with system encoding that can be read with QTextCodec::codecForLocale() then you should use this method:
QString QString::fromLocal8Bit(const char * str, int size = -1)
const char* str = "zażółć gęślą jaźń"; // latin2 source file and system encoding
QString qstr = QString::fromLocal8Bit(str);
If you have const char * that's UTF8 encoded then you'll need to use this method:
QString QString::fromUtf8(const char * str, int size = -1)
const char* str = read_raw("hello.txt"); // assuming hello.txt is UTF8 encoded, and read_raw() reads bytes from file into memory and returns pointer to the first byte as const char*
QString qstr = QString::fromUtf8(str);
There's also method for const ushort * containing UTF16 encoded string:
QString QString::fromUtf16(const ushort * unicode, int size = -1)
const ushort* str = read_raw("hello.txt"); // assuming hello.txt is UTF16 encoded, and read_raw() reads bytes from file into memory and returns pointer to the first byte as const ushort*
QString qstr = QString::fromUtf16(str);
Alternative way:
std::string s = "This is an STL string";
QString qs = QString::fromAscii(s.data(), s.size());
This has the advantage of not using .c_str() which might cause the std::string to copy itself in case there is no place to add the '\0' at the end.
std::string s = "Sambuca";
QString q = s.c_str();
Warning: This won't work if the std::string contains \0s.
I came across this question because I had a problem when following the answers, so I post my solution here.
The above examples all show samples with strings containing only ASCII values, in which case everything works fine. However, when dealing with strings in Windows whcih can also contain other characters, like german umlauts, then these solutions don't work
The only code that gives correct results in such cases is
std::string s = "Übernahme";
QString q = QString::fromLocal8Bit(s.c_str());
If you don't have to deal with such strings, then the above answers will work fine.
Do you mean a C string, as in a char* string, or a C++ std::string object?
Either way, you use the same constructor, as documented in the QT reference:
Qt QString Reference
For a regular C string, just use the main constructor:
char name[] = "Stack Overflow";
QString qname(name);
For a std::string, you obtain the char* to the buffer and pass that to the QString constructor:
std::string name2("Stack Overflow");
QString qname2(name2.c_str());
Moreover, to convert whatever you want, you can use the QVariant class.
for example:
std::string str("hello !");
qDebug() << QVariant(str.c_str()).toString();
int test = 10;
double titi = 5.42;
qDebug() << QVariant(test).toString();
qDebug() << QVariant(titi).toString();
qDebug() << QVariant(titi).toInt();
output
"hello !"
"10"
"5.42"
5
I have two CString s1 and CString s2. I need find the last entry s2 in s1.
I can find any metod in CString like in C# LastIndexOf.
I am nooby in c++. Thanks in advance.
CString has no such function. You have to write it yourself, e.g.
int LastIndexOf(const CString& s1, const CString& s2)
{
int found = -1;
int next_pos = 0;
for (;;)
{
next_pos = s1.Find(s2, next_pos);
if (next_pos == -1)
return found;
found = next_pos;
};
}
A more optimal algorithm would reverse the strings first, I'm leaving that as an exercise.
i adopted the answer from Andrey (to increment the next_pos, seems to cause an endless loop without it). aaand, since i don't have enough repu points yet (can't comment) i'll post it as a separate answer:
int LastIndexOf(const CString& s1, const CString& s2)
{
int start = s1.Find(s2, 0);
if (start >= 0)
{
while (start < s1.GetLength())
{
int idx = s1.Find(s2, start+1);
if (idx >= 0)
start = idx;
else
break;
}
}
return start;
}
There is no CString method to directly address your question. However, you can use a combination of CString::ReverseFind + _tcsncmp to first locate next occurrence of last character of substring and, if found, compare the whole substring from there.
CString is I think part of the "Microsoft Foundation Class Library" and is not Standard C++.
There is a reference including methods here:
http://msdn.microsoft.com/en-us/library/aa315043%28v=vs.60%29.aspx
I don't see anything to turn that directly into a std::string (which has a lot more methods), but it probably is not so hard, either (search for "CString to std::string" and you'll find some stuff).
Although they are presumably related, don't confuse this with a c-string, which is an array of chars from Standard C included in Standard C++.
I added this because I am trying to convert handle WStrings in Android NDK NDK does not support wide characters. I could use advice on how to do this. I think the asciiConvert method does not work anymore
typedef std::basic_string<wchar_t> WString;
WString val;
val=L"";
set_val(L"");
char* value=asciiConvert(get_val()); // value is 0x00000000
std::string token; // value is ""
if (strcmp(token.c_str(),value)==0) //ERROR HERE: INFINITE LOOP HERE I THINK since it will never be true.
HERE IS THE CONVERSION FUNCTION:
char* asciiConvert(const wchar_t* wideStr, char replSpace) // replSpace == -1
{
if (wideStr == NULL)
return NULL;
char* asciiStr = new char[wcslen(wideStr) + 10];
sprintf(asciiStr, "%S", wideStr);
if (replSpace >= 0)
{
int len = strlen(asciiStr);
while (len)
{
if (asciiStr[len] == ' ')
asciiStr[len] = replSpace;
len--;
}
}
return asciiStr;
}
UPDATE: the typedef is advised for some implementations which do not support wstring so I think I need, but now something to not work like above. Have not used C++ in a while so I could use very specific instructions on this.
Basically I have dozens of const wchar_t* foo(const wchar_t* a, const wchar_t& b)
and a quite a few wchar* [] as well as const wchar_t* memVariable; even virutal functions with these.
How about CrystalX for this? Is that the way to go?
After executing the code below, I see that the line
encoded = QString(DicResourceByteArray.toBase64().data());
gets too much RAM. Approximately 60MB.
How can I release it from memory?
Dic_block DicBlock;
qint64 Count;
int pos, len;
QByteArray DicResourceByteArray;
QDataStream out(&DicResourceByteArray, QIODevice::WriteOnly);
QString encoded;
while(DicInstance.readBlock(DicBlock))
{
if(DicBlock.type == 2)
{
pos = 0;
len = (unsigned char)DicBlock.data[pos++];
std::string filename( DicBlock.data+pos, len );
pos += len;
out.writeRawData(DicBlock.data + pos, DicBlock.length - pos);
encoded = QString(DicResourceByteArray.toBase64().data());
QString strQuery = QString("INSERT INTO Dictionary_Resources([FileName], [ImageBasedOn64]) values('%1', '%2')").arg(QString::fromStdString(filename), encoded);
query->exec(strQuery);
delete encoded;
}
}
delete query;
db.close();
//...
DicInstance.close();
First thing: grab the data array with .toBase64().constData(), this avoids a possible copy of your data.
Second thing: Move the declaration of QString encoded; into the if-block, this ensures, that after the if-block memory gets released.
Third thing: remove the delete encoded;! (Astonishing that it compiles as encoded is not a pointer).
You don't need delete encoded, the QString is going to be automatically deleted (and released from memory) at the end of your block.
You're doing things very inefficiently by copying the contents of encoded into strQuery. Bind it as a value in your query instead.
What is the right way to compare two CComBSTRs? I tried to use
bool operator ==(
const CComBSTR& bstrSrc
) const throw( );
However it always return false even two ComBSTRs are the same. It did not work correctly.
Do I have to convert CComBSTRs to ANSI string first and then use strcmp?
Thanks!
-bc
You should probably use VarBstrCmp.
EDIT: this is actually what CComBSTR::operator== does, so without further context, your code may be incorrect.
BSTRs (and therefore CComBSTRs) are usually Unicode strings. You can use wcscmp() (or wcsicmp() for case-insensitive comparison).
Beware that encapsulated BSTR can be null which is a legal representation for an empty string and this should be treated as a special case, otherwise your program might run into undefined behaviour (most likely just crash).
To properly compare BSTR values which may contain embedded null characters you need to use something like this:
bool EqualBSTR(const BSTR String1, const BSTR String2, bool IgnoreCase = false)
{
if (String1 == nullptr || String2 == nullptr) {
return false;
}
const size_t MaxCount = std::min(static_cast<size_t>(SysStringLen(String1)), static_cast<size_t>(SysStringLen(String2)));
if (IgnoreCase) {
return _wcsnicmp(String1, String2, MaxCount) == 0;
} else {
return wcsncmp(String1, String2, MaxCount) == 0;
}
}
BSTRsAreEqual(BSTR bstr1, BSTR bstr2, VARIANT_BOOL* boolptrEqual)
{
CString s1, s2;
s1 = bstr1;
s2 = bstr2;
if (s1 == s2) {
*boolptrEqual = true;
} else {
*boolptrEqual = false;
}
}