Comparing international strings - c++

What I am trying to do is comparin 2 QStrings that have special characters (French)
first I recieved from server as json data saved in txtInfo
txtInfo = "Présenter";
When I am having condition like this it's not gonna work(its not gonna set state.)
if (txtInfo == "Présenter"){
m_appState = 8;
m_appStateString = AppStatesArray[m_appState];
}
else {
m_appState = -1;
m_appStateString = "UNKNOWN";
}
What I am missing? What if I would like to compare not French but Chinese?
Thank you very much

Since Qt 5 QString's operator== performs fromUtf8 conversion on the character array being compared to it. But if your source file (.cpp) isn't using utf8 you need to build your own QString.
Depending on your source file's (.cpp) encoding:
Utf8:
QString compared = QString::fromUtf8("Présenter");
if (txtInfo == QString::fromUtf8("Présenter")){
local 8-bit:
QString compared = QString::fromLocal8Bit("Présenter");
if (txtInfo == QString::fromUtf8("Présenter")){
For 100% correctness, don't forget to normalize your strings:
txtInfo = txtInfo.normalized(QString::NormalizationForm_D);
QString compared = /* the correct form for you */;
if (txtInfo == compared.normalized(QString::NormalizationForm_D)){

Related

Getting a String Argument From Node Add On

I am trying to pass a string to a C++ add on in Node.js. I am using the Nan library as seems to be recommended. For the equivalent task with a number I do the following:
NAN_METHOD(funcName) {
if (!info[0]->IsUint32()) {
Nan::ThrowError("Argument must be an unsigned int 32");
}
v8::Local<v8::Context> ctxt = info.GetIsolate()->GetCurrentContext();
uint32_t blocks;
info[0]->Uint32Value(ctxt).To(&blocks);
}
after which I can work with the blocks variable. There doesn't seem to be any equivalent StringValue function. I have tried info[0]->ToString(ctxt) but this gives me a MaybeLocal which seems to be a null check around local. Once I convert to v8::Local<v8::String> I have no idea how to actually access the string value. I have also tried info[0]->Cast but this also does not work. Any help would be appreciated.
Do not forget that V8 stores internally all strings as UTF-16 unlike most other languages/frameworks which use UTF-8.
Here is a sample code:
if (info.Length() < num + 1) {
Nan::ThrowError(name " must be given");
return;
}
if (!info[num]->IsString()) {
Nan::ThrowTypeError(name " must be a string");
return;
}
std::string var = (*Nan::Utf8String(info[num]));
You can check this which has many defines for decoding various values passed to a NaN C++ method from JS:
https://github.com/mmomtchev/node-gdal-async/blob/983a5df62ceb85f8c1fb580d6d7d496f38db36cd/src/gdal_common.hpp#L429

How to Concatenate Unicode string into a character string to pass into mysql call

I am trying to concatenate an array of strings into a character array - but one of the strings is in a foreign language (why I need UTF8). I can see the UTF8 string in their appropriate language in the debugger (Visual Studio) after I read it from the database and put it into the wxString array, but when I try to concatenate the string to the array, t never gets put in there.
I have tried variable.mb_str()
variable.mb.str().data(). Neither seems to work in the strcat
for my Language data. The other data is concatenated fine. All of the data comes from a MariaDB database call.
int i, numRows;
wxString query;
wxString sortby;
wxString group_list;
wxString *stringGroups;
char holdString[400];
/* Try UTF Force */
query.Printf(_("set names 'utf8'"));
mysql_query(mDb, query.mb_str());
result = mysql_store_result(mDb);
mysql_free_result(result);
query.Printf(_("select GROUP_NAME from USER_PERMS where USER_NAME =
\"%s\"
ORDER BY GROUP_NAME "), riv_getuser().c_str() );
mysql_query(mDb, query.mb_str());
result = mysql_store_result(mDb);
numRows = mysql_num_rows(result);
stringGroups = new wxString[numRows + 1];
i = 0;
while ((row = mysql_fetch_row(result)))
{
stringGroups[i] = wxString(row[0], wxConvUTF8);
i++;
}
mysql_free_result(result);
i = 0;
strcpy (holdString,"IN (\'");
while (i < numRows)
{
if (i != 0) strcat(holdString, "\', \'");
strcat(holdString, (const char *)stringGroups[i].mb_str().data());
i++;
}
strcat (holdString," \')");
-- END OF CODE --
--ACTUAL stringGroup that fails -- Debugger Watch Output
stringGroups[2] {m_impl=L"文字化け"...
I expect to get:
IN ( 'test' , 'test' , '文字化け' )
what I get
IN ( 'test','test2','' )
Don't use strcpy() and strcat() with wxString, this is just needlessly error-prone. If you use wxString in the first place, build the entire string you need and then utf8_str() method to get the buffer containing UTF-8 string contents which you can then pass to whatever function you need.
Do keep in mind that this buffer is temporary, so you can't rely on it continuing to exist if you don't make a copy of it or at least extend its lifetime, i.e.
auto const& buf = some_wx_string.utf8_str();
... now you can use buf.data() safely until the end of scope ...
To get UTF8 from wxString you need to call ToUTF8(). Similarly, for getting UTF8 into wxString there is FromUTF8(). Both are members of wxString and documented.
wxString::mb_str() converts to a multi-byte string in your current locale. Presumably the characters in your string aren't representable in your locale so the conversion fails and an empty string is returned.
You should pass wxConvUTF8 as a parameter or simply call utf8_str or ToUTF8 instead.

How to convert fetched string data to character array?

I am doing this IoT based project on displaying data to connected display( I've used the MAX7219 module, in this case) with the help of nodeMCU. The idea here is that the string which is stored in my firebase database is to be display on the led display.
I've had no trouble in getting the value from the database to my nodeMCU but there is this little problem with converting that string to char array since the code i am using( Max72xx_Message_serial, which was available as an example with the max72xx library) has used char array but i can only fetch the stored data in string format. I've modified that code so as to connect with firebase but the main issue is to convert the string fetched from the database to char array.
I tried toCharArray() but it still shows conversion error.
void readfromfirebase(void)
{
static uint8_t putIndex = 0;
int n=1;
while (Firebase.available())
{
newMessage[putIndex] = (char)Firebase.getString("Submit Message"); // this line produces the error
if ((newMessage[putIndex] == '\n') || (putIndex >= BUF_SIZE-3)) // end of message character or full buffer
{
// put in a message separator and end the string
newMessage[putIndex++] = ' ';
newMessage[putIndex] = '\0';
// restart the index for next filling spree and flag we have a message waiting
putIndex = 0;
newMessageAvailable = true;
}
else if (newMessage[putIndex] != '\r')
// Just save the next char in next location
{putIndex++;}
n++;
}
}
I think you are confusing the types
getString returns a String object wich can be converted to a char[] using the methods of the String class.
I assume your newMessage is of type char[] or char*.
Then I would advise you to go for the String.c_str() method, because it returns a C style null-terminated string, meaning a char*.
See https://www.arduino.cc/reference/en/language/variables/data-types/string/functions/c_str/ for reference.
It also sets the last character of the string to 0. So methods like strlen, strcmp etc will work.
! be carefull not to modify the array returned by c_str(), if you want to modify it you chould copy the char[] or use string.toCharArray(buf, len).
Your Code might then look like the following.
String msg = Firebase.getString("Submit Message");
newMessage = msg.c_str();
// rest of your code
If newMessage is a buffer storing multiple messages, meaning char* newMessage[3].
String msg = Firebase.getString("Submit Message");
newMessage[putIndex] = msg.c_str();
// rest of your code
Be careful, because you are storing multiple characters in an array, so use strcmp to compare these arrays!
If you are new to C I would recommend reading.
https://www.cprogramming.com/tutorial/c/lesson9.html
https://www.arduino.cc/reference/en/language/variables/data-types/stringobject/ (as pointed out by #gre_gor)

QString numbers stay the same in serial communication

I have trouble with reading serial data from an Arduino, and sending it to the UI. I found it to be a hassle to split all serial data into 3 seperate variables, and therefore used the left and mid to get the specific numbers. The problem now is that the numbers I get stays the same, eventhough I can see on an LCD display they change.
This is a section of the code:
void Dolle::serialReceived(){
ba = serial->readAll();
serialBuffer += QString::fromStdString(ba.toStdString());
QString bufferSplit = serialBuffer;
QString hum = bufferSplit.left(2);
QString temp = bufferSplit.mid(2, 2);
QString gas = bufferSplit.mid(4, 4);
if((hum.size()==2) && (temp.size()==2) && (gas.size()==4)){
ui->humLabel->setText("Humidity: "+hum+" %");
ui->tempLabel->setText("Temperature: "+temp+(char(176))+ "C");
ui->gasLabel->setText("Gas level: "+gas);
qDebug() << hum << temp << gas;
}
}
There are several problems:
You're appending to serialBuffer, but you never empty it out. The QIODevice already maintains an internal, resizable circular buffer for you, so a second one is not necessary.
You're going from binary representation to a QString via a std::string. That is completely unnecessary.
You're not explicit about what character encoding is used in the binary data.
The UI is updated repeatedly, instead of at most once per readyRead signal.
You're using magic constants. You should UTF-8 encode your source instead, or use a named QChar constant.
You're manually building strings using string operators, this impedes internationalization and maintainability.
You're using spaces as a mechanism to align the display in your UI. Perhaps you should design your UI in a different manner, so that such hacks won't be necessary.
I presume that your strings are separated somehow - perhaps each is in a separate line? In any case, you should keep reading the complete delimited strings from the device as long as they are available. The QIODevice::readLine method makes it easy in case of line-delimited data:
void Dolle::serialReceived() {
QString validLine;
while (serial->canReadLine()) {
auto binLine = serial->readLine();
auto line = QString::fromLatin1(binLine);
if (line.length() < 8)
continue;
validLine = line;
}
if (validLine.isEmpty()) return;
auto hum = line.left(2);
auto temp = line.mid(2, 2);
auto gas = line.mid(4, 4);
ui->humLabel->setText(QStringLiteral("Humidity: %1%").arg(hum));
ui->tempLabel->setText(QStringLiteral("Temperature: %1°C").arg(temp));
ui->gasLabel->setText(QStringLiteral("Gas level: %1").arg(gas));
}
Suppose that instead of line-separated data, your data arrives in fixed-size chunks. You'd process them in a similar fashion:
void Dolle::serialReceived() {
QString validPacket;
while (serial->bytesAvailable() >= 8) {
auto bin = serial->read(8);
auto packet = QString::fromLatin1(bin);
if (packet.length() < 8)
continue;
validPacket = packet;
}
...
}

insert utf-8 data in openldap with c api

What is the correct method to insert utf-8 data in an openldap database? I have data in a std::wstring which utf-8 encoded with:
std::wstring converted = boost::locale::conv::to_utf<wchar_t>(line, "Latin1");
When the string needs to added tot an ldapMod structure, i use this fuction:
std::string str8(const std::wstring& s) {
return boost::locale::conv::utf_to_utf<char>(s);
}
to convert from wstring to string. This is used in my function to create an LDAPMod:
LDAPMod ** y::ldap::server::createMods(dataset& values) {
LDAPMod ** mods = new LDAPMod*[values.elms() + 1];
mods[values.elms()] = NULL;
for(int i = 0; i < values.elms(); i++) {
mods[i] = new LDAPMod;
data & d = values.get(i);
switch (d.getType()) {
case NEW: mods[i]->mod_op = 0; break;
case ADD: mods[i]->mod_op = LDAP_MOD_ADD; break;
case MODIFY: mods[i]->mod_op = LDAP_MOD_REPLACE; break;
case DELETE: mods[i]->mod_op = LDAP_MOD_DELETE; break;
default: assert(false);
}
std::string type = str8(d.getValue(L"type"));
mods[i]->mod_type = new char[type.size() + 1];
std::copy(type.begin(), type.end(), mods[i]->mod_type);
mods[i]->mod_type[type.size()] = '\0';
mods[i]->mod_vals.modv_strvals = new char*[d.elms(L"values") + 1];
for(int j = 0; j < d.elms(L"values"); j++) {
std::string value = str8(d.getValue(L"values", j));
mods[i]->mod_vals.modv_strvals[j] = new char[value.size() + 1];
std::copy(value.begin(), value.end(), mods[i]->mod_vals.modv_strvals[j]);
mods[i]->mod_vals.modv_strvals[j][value.size()] = '\0';
}
mods[i]->mod_vals.modv_strvals[d.elms(L"values")] = NULL;
}
return mods;
}
The resulting LDAPMod is passed on to ldap_modify_ext_s and works as long as i only use ASCII characters. But if other characters are present in the string I get an ldap operations error.
I've also tried this with the function provided by the ldap library (ldap_x_wcs_to_utf8s) but the result is the same as with the boost conversion.
It's not the conversion itself that is wrong, because if I convert the modifications back to a std::wstring and show it in my program output, the encoding is still correct.
AFAIK openldap supports utf-8 since long, so I wonder if there's something else that must be done before this works?
I've looked into the openldap client/tools examples, but the utf-8 functions provided by the library are never used in there.
Update:
I noticed I can insert utf-8 characters like é into ldap with Apache Directory Studio. I can retrieve these values from ldap in my c++ program. But if I insert the same character again, without changing anything to that string, I get the ldap operations error again.
It turns out that my code was not wrong at all. My modifications tried to store the full name in the 'displayName' field as well as in 'gecos'. But apparently 'gecos' cannot handle utf8 data.
We don't actually use gecos anymore. The value was only present because of some software we used years ago, so I removed it from the directory.
What made it hard to find was that even though the loglevel was set to 'parse', this error was still not in the logs.
Because libldap can be such a hard nut to crack, I'll include a link to the complete code of the project i'm working on. It might serve as a starting point for other programmers. (Most of the code in tutorials I have found is outdated.)
https://github.com/yvanvds/yATools/tree/master/libadmintools/ldap