How to suppress unicode characters in QString or convert to latin1 - qt

Trying to insert some data from CSV to Firebird table in Qt. DB is in ASCII. When inserting some strings with non-ascii symbols get error:
Cannot transliterate character between character sets
Setting QSqlDatabase::setConnectOptions("ISC_DPB_LC_CTYPE=UTF8;") and converting column to UTF8 (CHARACTER SET UTF8) does not help - same error. Trying to suppress unicode characters with no luck as well:
QTextCodec *codec = QTextCodec::codecForName("latin1");
QByteArray encodedString = codec->fromUnicode(str);
str = QString(encodedString);
QString::toLatin1 () does not suppress characters as well. What solution could be here?

This piece of code should do what you need:
QString h("Honkäüö?ß#asdfe");
unsigned char * data = (unsigned char*)h.data();
QString result;
for(int i = 0; h.size()*2; i+=2) {
if(data[i] > 127) {
result.append("?");
} else {
result.append(QChar(data[i]));
}
}
Here is another, more robust, version:
QString h("Honkäüö?ß#asdfe");
QString result;
for(int i = 0; i < h.size(); ++i) {
QChar qc = h.at(i);
unsigned char c = *(unsigned char*)(&qc);
if(c >= 127) {
result.append("?");
} else if (QChar(c).isPrint()) {
result.append(QChar(c));
}
}
QString result is just used to show what is extracted. You could copy the data[i] in a char array or a append to a QByteArray.
result is Honk?????????#asdfe
This works well for 16bit characters. 32bit characters result in additional '?'s or other characters.

This code extract any unicode (emojis) from qstring (16 or 32 bits) and toReturn contain only characters from ASCII table ( unicode value less than 256 )
QString cleanQString(QString toClean) {
QString toReturn="";
for(int i=0;i<toClean.size();i++){
if(toClean.at(i).unicode()<256){
toReturn.append(toClean.at(i));
}
}
return toReturn;
}

Related

QT String to char * adds extra characters

I have a qTextEdit that I grab the text from (QString) and convert to a char* with this code:
QString msgQText = ui->textMsg->toPlainText();
size_t textSize = (size_t)msgQText.size();
if (textSize > 139) {
textSize = 139;
}
unsigned char * msgText = (unsigned char *)malloc(textSize);
memcpy(msgText, msgQText.toLocal8Bit().data(), textSize);
msgText[textSize] = '\0';
if (textSize > 0) {
Msg * newTextMsg = new Msg;
newTextMsg->type = 1; // text message type
newTextMsg->bitrate = 0;
newTextMsg->samplerate = 0;
newTextMsg->bufSize = (int)textSize;
newTextMsg->len = 0;
newTextMsg->buf = (char *)malloc(textSize);
memcpy((char *)newTextMsg->buf, (char *)msgText, textSize);
lPushToEnd(sendMsgList, newTextMsg, sizeof(Msg));
ui->sendRecList->addItem((char *)newTextMsg->buf);
ui->textMsg->clear();
}
I put the text into a qListBox, but it shows up like
However, the character array, if I print it out, does not have the extra characters.
I have tried checking the "compile using UTF-8" option, but it doesn't make a difference.
Also, I send the text using RS232, and the receiver side also displays the extra characters.
The receiver code is here:
m_serial->waitForReadyRead(200);
const QByteArray data = m_serial->readAll();
if (data.size() > 0) {
qDebug() << "New serial data: " << data;
QString str = QString(data);
if (str.contains("0x6F8C32E90A")) {
qDebug() << "TEST SUCCESSFUL!";
}
return data.data();
} else {
return NULL;
}
There is a difference between the size of a QString and the size of the QByteArray returned by toLocal8Bit(). A QString contains unicode text stored as UTF-16, while a QByteArray is "just" a char[].
A QByteArray is null-terminated, so you do not need to add it manually.
As #GM pointed out: msgText[textSize] = '\0'; is undefined behavior. You are writing to the textSize + 1 position of the msgText array.
This position may be owned by something else and may be overwritten, so you end up with a non null terminated string.
This should work:
QByteArray bytes = msgQText.toLocal8Bit();
size_t textSize = (size_t)bytes.size() + 1; // Add 1 for the final '\0'
unsigned char * msgText = (unsigned char *) malloc(textSize);
memcpy(msgText, bytes.constData(), textSize);
Additional tips:
Prefer using const functions on Qt types that are copy-on-write, e.g. use QBytearray::constData() instead of QByteArray::data(). The non-const functions can cause a deep-copy of the object.
Do not use malloc() and other C-style functions if possible. Here you could do:
unsigned char * msgText = new unsigned char[textSize]; and later delete[] msgText;.
Prefer using C++ casts (static_cast, reinterpret_cast, etc.) instead of C-style casts.
You are making 2 copies of the text (2 calls to memcpy), given your code only 1 seem to be enough.

Convert string as hex to hexadecimal

I have a function that takes an uint64_t variable. Normally I would do this:
irsend.sendNEC(result.value);
result.value is an uint64_t as hexadecimal (I think). If I do this:
String((uint32_t) results.value, HEX)
I get this:
FF02FD
If I do:
irsend.sendNEC(0x00FF02FD)
it works perfectly and is what I want.
Instead of grabbing the result.value, I want to write it as a string (because that's what I get from the GET request). How do I make "FF02FD" into 0x00FF02FD?
EDIT:
Maybe this makes it easier to understand:
GET: http://192.168.1.125/code=FF02FD
//Arduino grabs the FF02FD by doing:
for (int i = 0; i < server.args(); i++) {
if (server.argName(i) == "code") {
String code = server.arg(i);
irsend.sendNEC(code);
}
}
This is where I get the error:
no matching function for call to 'IRsend::sendNEC(String&)'
because:
void sendNEC(uint64_t data, uint16_t nbits = NEC_BITS, uint16_t repeat = 0);
Comment writeup:
As already suggested, a string containing a hexadecimal value can be converted to an actual integer value using the C standard library functions such as "string to unsigned long" (strtoul) or "string to unsigned long long" (strtoull). From Arduino-type String one can get the actual const char* to the data using the c_str() member function. All in all, one does a hex-string to integer conversion as
uint64_t StrToHex(const char* str)
{
return (uint64_t) strtoull(str, 0, 16);
}
Which can then in code be called as
for (int i = 0; i < server.args(); i++) {
if (server.argName(i) == "code") {
String code = server.arg(i);
irsend.sendNEC(StrToHex(code.c_str()));
}
}
Appendum: Be carefull about using int or long on different platforms. On a Arduino Uno/Nano with a 8-bit microcontroller, such as the ATMega328P, an int is a int16_t. On the 32-bit ESP8266 CPU, an int is int32_t.

Convert String to HEX on arduino platform

I am doing a small parser that should convert a string into an Hexadecimal value,I am using arduino as platform but I am getting stack with it.
My string is data = "5449"
where each element is an char, so I would like to translate it to a HEX value like dataHex = 0x54 0x59, and finally those values should be translate to ASCII as dataAscii= TI
How can I do this?
I was thinking of splitting it into an char array with dataCharArray = 54 49 and later converting those values to the chars T and I, but I am not sure whether or not that is the best way.
Thanks in advance,
regards!
I don't have arduino installed in my PC right now, so let's hope the following works:
char nibble2c(char c)
{
if ((c>='0') && (c<='9'))
return c-'0' ;
if ((c>='A') && (c<='F'))
return c+10-'A' ;
if ((c>='a') && (c<='a'))
return c+10-'a' ;
return -1 ;
}
char hex2c(char c1, char c2)
{
if(nibble2c(c2) >= 0)
return nibble2c(c1)*16+nibble2c(c2) ;
return nibble2c(c1) ;
}
String hex2str(char *data)
{
String result = "" ;
for (int i=0 ; nibble2c(data[i])>=0 ; i++)
{
result += hex2c(data[i],data[i+1]) ;
if(nibble2c(data[i+1])>=0)
i++ ;
}
return result;
}

Search QString character by character

I'm trying to parse a QString character by character with a while loop, but I can't figure out how to parse an individual character to char type. Here's my code, I know it's not optimal:
QString temp = (QString)t[0];
int i = 1;
while (t[i] != " ");
{
temp.append(t[i]);
i += 1;
}
I've seen the casting with toLocal8bit function, but whatever I try I just cannot adapt it to my code.
Qt Creator shows this error:
error: conversion from 'const char [2]' to 'QChar' is ambiguous
in line with the while function call
You can use C++ 11 range based for loop
for (auto chr : text)
{
if (!chr.isDigit()) // for exmpl.
return false;
}
Why don't you try that :
QString test = "test";
for(int i = 0; i< test.length(); i++)
{
if (test.at(i) != " ")
test.at(i).toLatin1();
}

Printing the contents of an array to a file

Pointer related question. I'm going through some example code that currently reads in data from a file called dataFile into a buffer. The reading is done inside a loop as follows:
unsigned char* buffer = (unsigned char*)malloc(1024*768*);
fread(buffer,1,1024*768,dataFile);
redPointer = buffer;
bluePointer = buffer+1024;
greenPointer = buffer+768;
Now, I want to try and write the entire contents of the array buffer to a file, so that I can save just those discrete images (and not have a large file). However, I am not entirely sure how to go about doing this.
I was trying to cout statements, however I get a print-out of garbage characters on the console and also a beep from the PC. So then I end my program.
Is there an alternative method other than this:
for (int i=0; i < (1024*768); i++) {
fprintf(myFile, "%6.4f , ", buffer[i]);
}
By declaring your buffer as a char*, any pointer arithmatic or array indexes will use sizeof(char) to calculate the offset. A char is 1 byte (8 bits).
I'm not sure what you are trying to do with the data in your buffer. Here are some ideas:
Print the value of each byte in decimal, encoded as ASCII text:
for (int i=0; i < (1024*768); i++) {
fprintf(myFile, "%d , ", buffer[i]);
}
Print the value of each byte in hexadecimal, encoded in ASCII text:
for (int i=0; i < (1024*768); i++) {
fprintf(myFile, "%x , ", buffer[i]);
}
Print the value of each floating point number, in decimal, encoded in ASCII text (I think my calculation of the array index is correct to process adjacent non-overlapping memory locations for each float):
for (int i=0; i < (1024*768); i += sizeof(float)) {
fprintf(myFile, "%6.4f , ", buffer[i]);
}
Split the buffer into three files, each one from a non-overlapping section of the buffer:
fwrite(redPointer, sizeof(char), 768, file1);
fwrite(greenPointer, sizeof(char), 1024-768, file2);
fwrite(bluePointer, sizeof(char), (1024*768)-1024, file3);
Reference for fwrite. Note that for the count parameter I simply hard-coded the offsets that you had hard-coded in your question. One could also subtract certain of the pointers to calculate the number of bytes in each region. Note also that the contents of these three files will only be sensible if those are sensibly independent sections of the original data.
Maybe this gives you some ideas.
Updated: so I created a complete program to compile and test the formatting behavior. This only prints the first 20 items from the buffer. It compiles (with gcc -std=c99) and runs. I created the file /tmp/data using ghex and simply filled in some random data.
#include <stdlib.h>
#include <stdio.h>
int main()
{
FILE* dataFile = fopen("/tmp/data", "rb");
if (dataFile == NULL)
{
printf("fopen() failed");
return -2;
}
unsigned char* buffer = (unsigned char*)malloc(1024*768);
if (buffer == NULL)
{
printf("malloc failed");
return -1;
}
const int bytesRead = fread(buffer,1,1024*768,dataFile);
printf("fread() read %d bytes\n", bytesRead);
// release file handle
fclose(dataFile); dataFile = NULL;
printf("\nDecimal:\n");
for (int i=0; i < (1024*768); i++) {
printf("%hd , ", buffer[i]);
if (i > 20) { break; }
}
printf("\n");
printf("\nHexadecimal:\n");
for (int i=0; i < (1024*768); i++) {
printf("%#0hx , ", buffer[i]);
if (i > 20) { break; }
}
printf("\n");
printf("\nFloat:\n");
for (int i=0; i < (1024*768); i += sizeof(float)) {
printf("%6.4f , ", (float)buffer[i]);
if (i > 20) { break; }
}
printf("\n");
return 0;
}

Resources