Extract number from Alphanumeric QString - c++

I have a QString of "s150 d300". How can I get the numbers from the QString and convert it into integer. Simply using 'toInt' is not working.
Let say, from the QString of "s150 d300", only the number after the alphabet 'd' is meaningful to me. So how can I extract the value of '300' from the string?
Thank you very much for your time.

Why all the trouble if you can just do:
#include <QDebug>
#include <QString>
const auto serialNumberStr = QStringLiteral("s150 d300");
int main()
{
const QRegExp rx(QLatin1Literal("[^0-9]+"));
const auto&& parts = serialNumberStr.split(rx, QString::SkipEmptyParts);
qDebug() << "2nd nbr:" << parts[1];
}
Prints out: 2nd nbr: "300"

One possible solution is to use regular expressions as shown below:
#include <QCoreApplication>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QString str = "s150 dd300s150 d301d302s15";
QRegExp rx("d(\\d+)");
QList<int> list;
int pos = 0;
while ((pos = rx.indexIn(str, pos)) != -1) {
list << rx.cap(1).toInt();
pos += rx.matchedLength();
}
qDebug()<<list;
return a.exec();
}
Output:
(300, 301, 302)
Thanks to the comment of #IlBeldus, and according to the information QRegExp will be deprecated, so I propose a solution using QRegularExpression:
Another solution:
QString str = "s150 dd300s150 d301d302s15";
QRegularExpression rx("d(\\d+)");
QList<int> list;
QRegularExpressionMatchIterator i = rx.globalMatch(str);
while (i.hasNext()) {
QRegularExpressionMatch match = i.next();
QString word = match.captured(1);
list << word.toInt();
}
qDebug()<<list;
Output:
(300, 301, 302)

If your string is split into space separated tokens like the example you gave you can simply get the value out of it by splitting it, then finding a token that meets your needs and then taking the number part of it. I used atoi after converting the qstring into something I'm more comfortable with but I think there's a more efficient way.
Although this isn't as flexible as regular expressions, it should give better performance for the example you provided.
#include <QCoreApplication>
int main() {
QString str = "s150 d300";
// foreach " " space separated token in the string
for (QString token : str.split(" "))
// starts with d and has number
if (token[0] == 'd' && token.length() > 1)
// print the number part of it
qDebug() <<atoi(token.toStdString().c_str() + 1);
}

There are already answers giving a suitable solution to this problem, but I think it might be also helpful to stress that QString::toInt won't work because the string being converted should be a textual representation of a number and in the given example it is an alpha-numeric expression in a non-standard notation, thus it is necessary to manually process it as already suggested in order to make it "understanable" for Qt to perform the convertion.

Related

Qt- Splitting strings but keep the delimiters in array

I am trying to split string using delimiters but I want to keep the delimiters in the array. Code :
QRegExp rx("(\\+|\\-|\\*|\\/)");
QStringList query = text.split(rx);
Input:
2+3
This will give me an array
2,3 but I want 2,+,3
Is there any way to do that ?
You can have a work around solution for your problem.
Try this code :
#include <iostream>
#include <QStringList>
#include <QRegExp>
int main()
{
QString text = "2+3-3-4/5+9+0"; // Input, you can write you own code to take input
QRegExp rx("(\\+|\\-|\\*|\\/)");
QStringList query = text.split(rx);
int count = 0;
int pos = 0;
while ((pos = rx.indexIn(text, pos)) != -1) {
++count;
pos += rx.matchedLength();
query.insert(count * 2-1, QString(text[pos - 1]));
}
return 0;
}
I don't think there's a function in Qt that does it for you, but you could easily reconstruct it. Pseudo code, because I don't know the exact syntax:
QStringList query = text.split(rx);
QStringList queryWithSeparators;
size_t pos = 0;
for (const auto part : query) {
queryWithSeparators.append(part);
pos += part.length;
if (pos + 1 < text.length) {
// we know that the separators are all 1 character long
queryWithSeparators.append(text.substring(pos, 1));
pos += 1;
}
}
This is ugly and difficult to understand. From you example it seems that you are trying to parse a mathematical expression. It's much easier to create a tokenizer which reads character-by-character than trying to use regular expressions for this task.
(If you really want to use split, you could first split it for all +, then split these strings at all - etc. This way you would know exactly what the separators are.)

In Qt; what is the best method to capitalise the first letter of every word in a QString?

I am thinking of regular expressions, but that is not exactly readable. There are also functions like s.toUpper() to consider, and probably other things as well.
So what is the best method for capitalising the first letter of words in a QString?
Using this example as a reference, you can do something like this:
QString toCamelCase(const QString& s)
{
QStringList parts = s.split(' ', QString::SkipEmptyParts);
for (int i = 0; i < parts.size(); ++i)
parts[i].replace(0, 1, parts[i][0].toUpper());
return parts.join(" ");
}
Exactly the same, but written differently :
QString toCamelCase(const QString& s)
{
QStringList cased;
foreach (QString word, s.split(" ", QString::SkipEmptyParts))cased << word.at(0).toUpper() + word.mid(1);
return cased.join(" ");
}
This uses more memory but is without pointer access (no brackets operator).
There is an alternative way of doing this which iterates using references to the words and modifies the first character using a QChar reference instead:
QString capitalise_each_word(const QString& sentence)
{
QStringList words = sentence.split(" ", Qt::SkipEmptyParts);
for (QString& word : words)
word.front() = word.front().toUpper();
return words.join(" ");
}
Note that Qt::SkipEmptyParts is required here (as in the other answers to this question) since the first character of each word is assumed to exist when capitalising. This assumption will not hold with Qt::KeepEmptyParts (the default).
Incredible C++/Qt... You just want to get some chars ored with 0x20...

C++: Regex: returns full string and not matched group

for those asking, the {0} allows selection of any one block within the sResult string separated by the | 0 is the first block
it needs to be dynamic for future expansion as that number will be configurable by users
So I am working on a regex to extract 1 portion of a string, however while it matches the results return are not what is expected.
std::string sResult = "MATCH_ME|BUT|NOT|ANYTHNG|ELSE";
std::regex pattern("^(?:[^|]+[|]){0}([^|;]+)");
std::smatch regMatch;
std::regex_search(sResult, regMatch, pattern);
if(regMatch[1].matched)
{
for( int i = 0; i < regMatch.size(); i++)
{
//SUBMATCH 0 = "MATCH_ME|BUT|NOT|ANYTHNG|ELSE"
//SUBMATCH 1 = "BUT|NOT|ANYTHNG|ELSE"
std::ssub_match sm = regMatch[i];
bValid = strcmp(regMatch[i].str().c_str(), pzPoint->_ptrTarget->_pzTag->szOPCItem);
}
}
For some reason I cannot figure out the code to get me just the MATCH_ME back so I can compare it to expected results list on the C++ side.
Anyone have any ideas on where I went wrong here.
It seems you're using regular expressions for what they haven't been designed for. You should first split your string at the delimiter | and apply regular expressions on the resulting tokens if you want to check them for validity.
By the way: The std::regex implementation in libstdc++ seems to be buggy. I just did some tests and found that even simple patterns containing escaped pipe characters like \\| failed to compile throwing a std::regex_error with no further information in the error message (GCC 4.8.1).
The following code example shows how to do what you are after - you compile this, then call it with a single numerical argument to extract that element of the input:
#include <iostream>
#include <cstring>
#include <regex>
int main(int argc, char *argv[]) {
char pat[100];
if (argc > 1) {
sprintf(pat, "^(?:[^|]+[|]){%s}([^|;]+)", argv[1]);
std::string sResult = "MATCH_ME|BUT|NOT|ANYTHNG|ELSE";
std::regex pattern(pat);
std::smatch regMatch;
std::regex_search(sResult, regMatch, pattern);
if(regMatch[1].matched)
{
std::ssub_match sm = regMatch[1];
std::cout << "The match is " << sm << std::endl;
//bValid = strcmp(regMatch[i].str().c_str(), pzPoint->_ptrTarget->_pzTag->szOPCItem);
}
}
return 0;
}
Creating an executable called match, you can then do
>> match 2
The match is NOT
which is what you wanted.
The regex, it turns out, works just fine - although as a matter of preference I would use \| instead of [|] for the first part.
Turns out the problem was on the C side in extracting the match, it had to be done more directly, below is the code that gets me exactly what I wanted out of the string so I can use it later.
std::string sResult = "MATCH_ME|BUT|NOT|ANYTHNG|ELSE";
std::regex pattern("^(?:[^|]+[|]){0}([^|;]+)");
std::smatch regMatch;
std::regex_search(sResult, regMatch, pattern);
if(regMatch[1].matched)
{
std::string theMatchedPortion = regMatch[1];
//the issue was not with the regex but in how I was retrieving the results.
//theMatchedPortion now equals "MATCH_ME" and by changing the number associated
with it I can navigate through the string
}

Forking out matches from a string

How to get all matches from a string using regex?
I have a string:
".+(.cpp$|.cxx$|.d$|.h$|.hpp$)"
and I would like to get only the cpp cxx d h and hpp parts.
EDIT:
So basically I would like to construct regex which would match any string of characters starting with dot and ending with $.
I've tried the pattern: "\\.[^$+]+" which is supposed to match dot and everything else except $ and plus one or more times but this gets just the first .cpp part and I need all of them
Since you mention Qt in your question, here is how you would do it using QRegExp:
#include <QtCore>
#include <QtDebug>
int main(int argc, char **argv) {
QCoreApplication app(argc, argv);
QString target(".+(.cpp$|.cxx$|.d$|.h$|.hpp$)");
QRegExp pattern("\\.(\\w+)\\$");
QStringList matches;
int pos = 0;
while ((pos = pattern.indexIn(target, pos)) != -1) {
matches << pattern.cap(1);
pos += pattern.matchedLength();
}
qDebug() << matches; // "cpp", "cxx", "d", "h", "hpp"
return app.exec();
}
There's no generic solution as it really depends on how your regex implementation works and how it can be called - and considering there's no standard one for C++ (yet), you should mention which one you're using.
First of all you have to escape ., if it's meant to match a . and not just "any character". Also, I'd change the regex: "\.(d|[ch](?:pp|xx)?)$". This way you keep the dot as well as the line ending outside your match.
For the actual call (which will depend on your implementation) you'll have to use some kind of MATCH_ALL or GLOBAL_MATCH flag or simply loop over your input string, always starting after the previous match. Considering the line ending, you might simply use it once per input line (as I don't know your input data).
Find the location of the last "." and test the remaining string against all the suffixes you're interested in.
Since you are only interested in the elements between the punctuation marks, you can use them as separator to split the string with QStringList::split:
QString target = ".+(.cpp$|.cxx$|.d$|.h$|.hpp$)";
QStringList extensions = target.split(QRegExp("\\W+"), QString::SkipEmptyParts);
qDebug() << extensions; // ("cpp", "cxx", "d", "h", "hpp")

QString splitting multiple delimiters

I'm having trouble splitting a QString properly. Unless I'm mistaken, for multiple delimiters I need a regex, and I can't seem to figure out an expression as I'm quite new to them.
the string is text input from a file:
f 523/845/1 524/846/2 562/847/3 564/848/4
I need each number seperately to put into an array.
Some codes....
QStringList x;
QString line = in.readLine();
while (!line.isNull()) {
QRegExp sep("\\s*/*");
x = line.split(sep);
Any pointers?
Cheers
Change your regular expression like this:
QRegExp sep("(\\s+|/)");
then x will have every number.
I found it quite useful to try out RegEx's interactively. Nowadays there are a lot of online tools even, for example: http://gskinner.com/RegExr/
You can put your search text there and play with the RegEx to see what is matched when.
You could use the strtok function, which split a QString with one or more different tokens.
It would be like this:
QString a = "f 523/845/1 524/846/2 562/847/3 564/848/4";
QByteArray ba = a.toLocal8Bit();
char *myString = ba.data();
char *p = strtok(myString, " /");
while (p) {
qDebug() << "p : " << p;
p = strtok(NULL, " /");
}
You can set as many tokens as you need. For further info visit the cplusplus page of this particular function. http://www.cplusplus.com/reference/cstring/strtok/
Regards!.