Search QString character by character - qt

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();
}

Related

memmove implementation throws segmentation fault while copying a character array

Hi I tried to write my own version of memmove and I find the following code resulting in a segmentation fault. It would be great if someone could help me figure out why this behavior would occur!
However, when I use something like:
char source[20] = "Hello, this is Piranava", the code works fine!
void *memmoveLocal(void *dest, const void *src, unsigned int n)
{
char *destL = dest;
const char *srcL = src;
int i = 0;
if(dest == NULL || src == NULL)
{
return NULL;
}
else
{
// if dest comes before source, even if there's an overlap, we should move forward
// because if there's an overlap (when dest < src) and we move backward, we'd overwrite the overlapping bytes in src
if(destL < srcL)
{
printf("Forward\n");
while(i < n)
{
destL[i] = srcL[i];
i++;
}
}
else // in all other cases (even if there's overlap or no overlap, we can move backward)
{
printf("Backward\n");
i = n - 1;
while(i >= 0)
{
destL[i] = srcL[i];
i--;
}
}
}
return dest;
}
void main()
{
char *source = "Hello, this is ABC";
char *destination = malloc(strlen(source)+1);
memmoveLocal(source+5, source, 5);
printf("Source: %s \nDestination: %s, size: %d\n", source, destination, strlen(destination));
}
However, if I replace
char *source = "Hello, this is ABC";
with
char source[20] = "Hello, this is ABC";
, it works fine!
memmoveLocal(source+5, source, 5);
You are trying to overwrite a string literal, which is not writable.
Did you intend to memmoveLocal(destination, source+5, 5) instead?
char source[20] = "Hello, this is ABC";
That turns source from a string literal into a char[] array initialized with a string literal. The array is writable, so your program no longer crashes.

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.

How to suppress unicode characters in QString or convert to latin1

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;
}

How to split a string using a specific delimiter in Arduino?

I have a String variable and I want to extract the three substrings separeted by ; to three string variables.
String application_command = "{10,12; 4,5; 2}";
I cannot use substring method because this string can be like any of the following or similar patterns also.
String application_command = "{10,12,13,9,1; 4,5; 2}"
String application_command = "{7; 1,2,14; 1}"
The only thing that is common in these patterns is there are three sections separated by ;.
Any insight is much appreciated.
Thank you
I think you need a split-string-into-string-array function with a custom separator character.
There are already several sources on the web and at stackoverflow (e.g. Split String into String array).
// https://stackoverflow.com/questions/9072320/split-string-into-string-array
String getValue(String data, char separator, int index)
{
int found = 0;
int strIndex[] = {0, -1};
int maxIndex = data.length()-1;
for(int i=0; i<=maxIndex && found<=index; i++){
if(data.charAt(i)==separator || i==maxIndex){
found++;
strIndex[0] = strIndex[1]+1;
strIndex[1] = (i == maxIndex) ? i+1 : i;
}
}
return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
}
You can use this function as follows (with ";" as separator):
String part01 = getValue(application_command,';',0);
String part02 = getValue(application_command,';',1);
String part03 = getValue(application_command,';',2);
EDIT: correct single quotes and add semicolons in the example.
The new SafeString Arduino library (available from the library manager) provides a number of tokenizing/substring methods without the heap fragmentation of the String class
See https://www.forward.com.au/pfod/ArduinoProgramming/SafeString/index.html
for a detailed tutorial
In this case your can use
#include "SafeString.h"
void setup() {
Serial.begin(9600);
createSafeString(appCmd, 50); // large enought for the largest cmd
createSafeString(token1, 20);
createSafeString(token2, 20);
createSafeString(token3, 20);
appCmd = "{10,12,13,9,1; 4,5; 2}";
size_t nextIdx = 1; //step over leading {
nextIdx = appCmd.stoken(token1, nextIdx, ";}");
nextIdx++; //step over delimiter
nextIdx = appCmd.stoken(token2, nextIdx, ";}");
nextIdx++; //step over delimiter
nextIdx = appCmd.stoken(token3, nextIdx, ";}");
nextIdx++; //step over delimiter
// can trim tokens if needed e.g. token1.trim()
Serial.println(token1);
Serial.println(token2);
Serial.println(token3);
}
void loop() {
}
Also look at pfodParser which parses these types of messages { } for use by pfodApp.
Do not forget to call delete[] to free the memory after the use of the array, that said here is my solution:
String* split(String& v, char delimiter, int& length) {
length = 1;
bool found = false;
// Figure out how many itens the array should have
for (int i = 0; i < v.length(); i++) {
if (v[i] == delimiter) {
length++;
found = true;
}
}
// If the delimiter is found than create the array
// and split the String
if (found) {
// Create array
String* valores = new String[length];
// Split the string into array
int i = 0;
for (int itemIndex = 0; itemIndex < length; itemIndex++) {
for (; i < v.length(); i++) {
if (v[i] == delimiter) {
i++;
break;
}
valores[itemIndex] += v[i];
}
}
// Done, return the values
return valores;
}
// No delimiter found
return nullptr;
}
Here is an example of how to use:
void loop() {
String test = "1,2,3,4,5";
int qtde;
String* t = split(test, ',', qtde);
for (int i = 0; i < qtde; i++) {
Serial.println(t[i]);
delay(1000);
}
delete[] t;
}

passing different structure type in c for functions

I have a following code :
typedef struct PStruct{
int len;
char* data;
}PointerStruct;
typedef struct AStruct{
int len;
char data[256];
}ArrayStruct;
void checkFunc(PointerStruct* myData)
{
if (0 == myData || 0 == myData->data){
printf("error\n");
}
}
int main()
{
ArrayStruct my_data;
my_data.len = 256;
char data[] = "data is sent";
my_data.data = &data;
checkFunc((PointerStruct*)my_data);
return 0;
}
is there any wrong in passing structure which has array. where as the required is pointer.
please let me know.
There are a couple of points to be considered in your program.
char data[] = "data is sent";
This is a character array of 13 characters. Hence, my_data.data = &data; will give a compilation error as shown below
error: incompatible types when assigning to type 'char[256]' from type 'char (*)[13]'
To copy your string, you could probably use strcpy as shown below
strcpy(my_data.data, data);
Next point is passing the pointer to the object. In this call, checkFunc((PointerStruct*)my_data);, you are passing the instance of the object to the function call, but are type-casting as a pointer. You would face compilation issues due to the mismatch of the datatypes as error: cannot convert to a pointer type
To overcome this error, you should pass a reference to your my_data object as checkFunc((PointerStruct*) &my_data);. Hence, your new main function would look like
int main()
{
ArrayStruct my_data;
my_data.len = 256;
char data[] = "data is sent";
//my_data.data = &data;
strcpy(my_data.data, data); // Use of strcpy. You would require to include <string.h>
checkFunc((PointerStruct*)(&my_data)); // Pass a reference and not by value
return 0;
}
With these changes, your code should work fine.

Resources