Do QString's toUpper()/toLower() member functions only convert Latin alpha characters? - qt

According to the documentation QString's toUpper() and toLower() member functions convert in the C-locale. Does it mean that only Posix Portable Character Set characters (Latin A-Z/a-z) are converted and any international unicode characters are left as-is?

We can easily test this with the simple test program here:
#include <QString>
#include <iostream>
int main()
{
QString s("БΣTest3φب");
std::cout << "String: " << s.toStdString() << std::endl;
std::cout << "Lower: " << s.toLower().toStdString() << std::endl;
std::cout << "Upper: " << s.toUpper().toStdString() << std::endl;
return 0;
}
Which returns:
09:48:48: Starting /home/tzig/test/test ...
String: БΣTest3φب
Lower: бσtest3φب
Upper: БΣTEST3Φب
09:48:49: /home/tzig/test/test exited with code 0
So we know that:
Cyrillic letters work fine
Latin letters work fine
Numbers are untouched
Greek letters work fine
Arabic letters don't have uppercase/lowercase so they are untouched
Feel free to test other Unicode characters with the test program.

Related

How to use void QTextStream::setRealNumberNotation

For a purpose I need to use void QTextStream::setRealNumberNotation(RealNumberNotation notation). I looked at so-called Docs for it, but there is no example for beginners! (It's here)
For example:
QString ss;
QTextStream (&ss);
// here how to use it
Here is an example of what setRealNumberNotation does and how you can use it
QString mystring;
QTextStream bla(&mystring);
bla.setRealNumberNotation(QTextStream::ScientificNotation);
bla << 0.000123;
qDebug() << mystring;
bla.setRealNumberNotation(QTextStream::FixedNotation);
mystring.clear();
bla << 0.000123;
qDebug() << mystring;
This prints out the following:
"1.230000e-04"
"0.000123"
Some more Details about the options for setRealNumberNotation. The Qt Documentation lists 3 Options
ScientificNotation # Scientific notation
FixedNotation # Fixed-point notation
SmartNotation # Scientific or fixed-point notation
SmartNotation uses the one which makes most sense like printf() %g conversion specifier. If you want to know how printf decides what makes most sense read the printf documentation

Calling a method from a different .cpp file

I want to save some data as a text file, the first txt file will contain header information, the other text file will save data streamed from sensors, so with the help from the internet I created the following "datalogger.cpp" file
#include "datalogger.h"
#include <QDebug>
#include <iostream>
#include <QFile>
DataLogger::DataLogger(QObject *parent) : QObject(parent)
{
}
DataLogger::~DataLogger(){
}
void DataLogger::save(DataStream &input){
saveAsText(input);
}
void DataLogger::saveAsText(DataStream &input){
QTextStream outHeader(&outFileHeader);
outHeader << "[CAPTURE SETTINGS]\n"
<< "Filename: " << SettingsSingleton::instance().getFileName() << ".txt \n"
<< "Samples: " << QString::number(input.size()) << "\n"
<< "Duration: " << QString::number(input.back().time) << "ms \n"
<< "Sample rate: " << QString::number(SettingsSingleton::instance().getSampleRate()) << " Hz\n"
<< "Source: " << SettingsSingleton::instance().getSource() << "\n"
outFileHeader.close();
}
QFile outFile(SettingsSingleton::instance().getFileName() + ".txt");
QTextStream out(&outFile);
for (int i ; i<input.size();i++){
const EcgStreamObject tmp=input.at(i);
out << tmp.toText() << endl; //"\n";
}
outFile.close();
}
}
I have my "DataStream" input variable that I want to pass to the method and save as a ".txt" file, however I do no know how to call the method "void DataLogger::save(DataStream &input)" from a different ".cpp" file where the DataStream variable is located.
I am extremely new to c++ please it as simple as possible please.
Thank you in advance
If I get your question right, it is about how to create and use a header file in c++.
There is already a lot of information about this, for example this article from cplusplus.com or this from learncpp.com.
All you should need to do is add "datalogger.h" to your other file.
When you call the method DataLogger::save from your other file, the program will search for an implementation that was linked to your program (i.e. the file you posted here) and use that to actually perform the work.
Stefan's answer is probably important to look at too as it will cover this case and some other basics if you are going to be working in C/C++ long term.

Unexpected Behavior of QRegularExpression

I've just started switching to QRegularExpression, and I'm using it to tokenize a string with multiple delimiter possibilities. I've encountered a surprising behavior, which seems to me to be a bug. I'm using Qt 5.5.1 on Windows.
Here's sample code:
#include <QRegularExpression>
#include <QString>
#include <QtDebug>
int main(int argc, char *argv[])
{
Q_UNUSED (argc);
Q_UNUSED (argv);
QRegularExpression regex ("^ ");
qDebug () << "Expected: " << QString ("M 100").indexOf(regex);
qDebug () << "NOT expected:" << QString ("M 100").indexOf(regex, 1);
qDebug () << "Expected: " << QString (" 100").indexOf(regex);
QRegularExpression regex1 (" ");
qDebug () << "Expected: " << QString ("M 100").indexOf(regex1);
}
And the output:
Expected: -1
NOT expected: -1
Expected: 0
Expected: 1
The use of the caret (^) when used with a starting position other than 0 in the "indexOf" call is preventing the expression from matching. Intuitively, I expected that the caret matches the string at the position that I specified. Instead, it simply never matches.
I'm going to switch my tokenizing to use splitRref to avoid this problem. While that's probably slightly cleaner anyway, I need to understand whether this is correct behavior or if I should be reporting a bug to Qt.
UPDATE: Using splitRef doesn't entirely solve my problem because I need to use a regular expression to detect if some tokens are floating point numbers, and I can't use a QRegularExpression with QStringRef. For that possibility, I have to convert my QStringRef token into an actual QString, which was what I was trying to avoid in the first place.
^ matches at the beginning of the subject string, or after a newline when in multiline mode. The offset does not alter these semantics. Hence, matching /^ / (in regex notation) against M 100 at offset 1 correctly results in no match.
Perhaps you want \G? From pcrepattern(3):
\G matches at the first matching position in the subject
The \G assertion is true only when the current matching position is at the start point of the match, as specified by the startoffset argument of pcre_exec(). It differs from \A when the value of startoffset is non-zero.
With that, this code:
QRegularExpression regex ("\\G ");
qDebug () << "Expected: " << QString ("M 100").indexOf(regex);
qDebug () << "NOT expected:" << QString ("M 100").indexOf(regex, 1);
qDebug () << "Expected: " << QString (" 100").indexOf(regex);
prints
Expected: -1
NOT expected: 1
Expected: 0

Pass a string from ECL to C++

I'm trying to get into the fascinating world of Common Lisp embedded in C++. My problem is that I can't manage to read and print from c++ a string returned by a lisp function defined in ECL.
In C++ I have this function to run arbitrary Lisp expressions:
cl_object lisp(const std::string & call) {
return cl_safe_eval(c_string_to_object(call.c_str()), Cnil, Cnil);
}
I can do it with a number in this way:
ECL:
(defun return-a-number () 5.2)
read and print in C++:
auto x = ecl_to_float(lisp("(return-a-number)"));
std::cout << "The number is " << x << std::endl;
Everything is set and works fine, but I don't know to do it with a string instead of a number. This is what I have tried:
ECL:
(defun return-a-string () "Hello")
C++:
cl_object y = lisp("(return-a-string)");
std::cout << "A string: " << y << std::endl;
And the result of printing the string is this:
A string: 0x3188b00
that I guess is the address of the string.
Here it is a capture of the debugger and the contents of the y cl_object. y->string.self type is an ecl_character.
Debug
(Starting from #coredump's answer that the string.self field provides the result.)
The string.self field is defined as type ecl_character* (ecl/object.h), which appears to be given in ecl/config.h as type int (although I suspect this is slightly platform dependent). Therefore, you will not be able to just print it as if it was a character array.
The way I found worked for me was to reinterpret it as a wchar_t (i.e. a unicode character). Unfortunately, I'm reasonably sure this isn't portable and depends both on how ecl is configured and the C++ compiler.
// basic check that this should work
static_assert(sizeof(ecl_character)==sizeof(wchar_t),"sizes must be the same");
std::wcout << "A string: " << reinterpret_cast<wchar_t*>(y->string.self) << std::endl;
// prints hello, as required
// note the use of wcout
The alternative is to use the lisp type base-string which does use char (base-char in lisp) as its character type. The lisp code then reads
(defun return-a-base-string ()
(coerce "Hello" 'base-string))
(there may be more elegant ways to do the conversion to base-string but I don't know them).
To print in C++
cl_object y2 = lisp("(return-a-base-string)");
std::cout << "Another: " << y2->base_string.self << std::endl;
(note that you can't mix wcout and cout in the same program)
According to section 2.6 Strings of The ECL Manual, I think that the actual character array is found by accessing the string.self field of the returned object. Can you try the following?
std::cout << y->string.self << std::endl;
std::string str {""};
cl_object y2 = lisp("(return-a-base-string)");
//get dimension
int j = y2->string.dim;
//get pointer
ecl_character* selv = y2->string.self;
//do simple pointer addition
for(int i=0;i<j;i++){
str += (*(selv+i));
}
//do whatever you want to str
this code works when the string is build from ecl_characters
from the documentation:
"ECL defines two C types to hold its characters: ecl_base_char and ecl_character.
When ECL is built without Unicode, they both coincide and typically match unsigned char, to cover the 256 codes that are needed.
When ECL is built with Unicode, the two types are no longer equivalent, with ecl_character being larger.
For your code to be portable and future proof, use both types to really express what you intend to do."
On my system the return-a-base-string is not needed, but I think it could be good to add for compatibility. I use the (ecl) embedded CLISP 16.1.2 version.
The following piece of code reads a string from lisp and converts to C++ strings types - std::string and c-string- and store them on C++ variables:
// strings initializations: string and c-string
std::string str2 {""};
char str_c[99] = " ";
// text read from clisp, whatever clisp function that returns string type
cl_object cl_text = lisp("(coerce (text-from-lisp X) 'base-string)");
//cl_object cl_text = lisp("(text-from-lisp X)"); // no base string conversions
// catch dimension
int cl_text_dim = cl_text->string.dim;
// complete c-string char by char
for(int ind=0;i<cl_text_dim;i++){
str_c[i] = ecl_char(cl_text,i); // ecl function to get char from cl_object
}
str_c[cl_text_dim] ='\0'; // end of the c-string
str2 = str_c; // get the string on the other string type
std::cout << "Dim: " << cl_ text_dim << " C-String var: " << str_c() << " String var << str2 << std::endl;
It is a slow process as passing char by char but it is the only way by the moment I know. Hope it helps. Greetings!

Reading more than one value into variables using QInputDialog

I have to write a small QT program that reads in 3 mark percentages separated by commas and then do some further calculations on the marks... I have to use QInputDialog to do this but it seems like it's only possible to read in one value at a time.
at this stage I am only trying to read in and display the three marks.
When I run this code QTCreator stops working and I have to end the process in task manager.
Any idea how I can approach this would be much appreciated. Should I read in a string and then convert that to double values or is there a simpler way?
Thanks in advance.
Code:
#include <QTGui>
#include <QApplication>
#include <QString>
#include <QTextStream>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QTextStream cin(stdin, QIODevice::ReadOnly);
QTextStream cout(stdout, QIODevice::WriteOnly);
double mark1, mark2, mark3;
double passMarkNeeded = 0;
QInputDialog::getDouble(0, "Enter marks", "Marks", 1);
cin >> mark1 >> mark2 >> mark3;
cout << "User entered " << mark1 << mark2 << mark3;
return EXIT_SUCCESS;
}
Obviously you cannot use QInputDialog::getDouble because it won't allow you to input 3 values separated by commas. You should use QInputDialog::getText, QString::split and QString::toDouble:
QStringList list = QInputDialog::getText(0, "Input values", "Input values:").split(",");
if (list.count() == 3) {
double a = list[0].toDouble(),
b = list[1].toDouble(),
c = list[2].toDouble();
qDebug() << "Values:" << a << b << c;
}
I'm not sure why you use QInputDialog and the standard input (cin). QInputDialog is for GUI apps, and cin is console apps. It's strange and pointless to use them together in such a way.

Resources