I'm in search for an easy and foolproof way to convert an arbitrary QStringList to a single QString and back.
QStringList fruits;
fruits << "Banana", "Apple", "Orange";
QString packedFruits = pack(fruits);
QStringList unpackFruits = unpack(packedFruits);
// Should be true
// fruits == unpackFruits;
What might be the easiest solution for this kind of problem?
From QStringList to QString - QStringList::join:
Joins all the string list's strings into a single string with each element separated by the given separator (which can be an empty string).
QString pack(QStringList const& list)
{
return list.join(reserved_separator);
}
From QString to QStringList - QString::split:
Splits the string into substrings wherever sep occurs, and returns the list of those strings. If sep does not match anywhere in the string, split() returns a single-element list containing this string.
QStringList unpack(QString const& string)
{
return string.split(reserved_separator);
}
Previous answers mentioned QString::split and QStringList::join which is the correct way, but if the separator you choose is included in any of the strings it will break your conversion.
You must prevent strings in the list to contain your separator with one of the following techniques:
Throw an error before QStringList::join if any string includes the separator
Ensure they can not contain the separator (for example storing the string with its QByteArray::toHex(myString.toLatin1()) representation, then using a separator that has character(s) outside of the range 0..9 and a..f. Then convert back with QString::fromLatin1(QByteArray::fromHex(myHexString)) afterward
Use any separator regardless if the strings contain it, but implement an escape logic for it before the join(), and an un-escape logic after the split(), so that the separator is never present in any of the strings at the time of join, but all instances of it will be restored.
Use QStringList::join() :
QStringList strList;
strList << "Banana" << "Apple" << "Orange" ;
QString str = strList.join(""); // str = "BananaAppleOrange";
str = strList.join(","); // str = "Banana,Apple,Orange";
Related
I have a qstring of directory structure and need to take the second last element after "/" into a new qstring
"C:/Users/emb/Documents/AutoConnectTest/02/Job_0"
How to save 02 into a new QString
You can use QString split function.
Splits the string into substrings wherever sep occurs, and returns the list of those strings.
this code split all section by "/" and merge two second from last.
QString string = "C:/Users/emb/Documents/AutoConnectTest/02/Job_0";
QStringList lst = string.split('/');
qDebug() << lst[lst.count()-2] + "/" + lst[lst.count()-1];
Output:
"02/Job_0"
I have a C++ function that accepts strings in below format:
<WORD>: [VALUE]; <ANOTHER WORD>: [VALUE]; ...
This is the function:
std::wstring ExtractSubStringFromString(const std::wstring String, const std::wstring SubString) {
std::wstring S = std::wstring(String), SS = std::wstring(SubString), NS;
size_t ColonCount = NULL, SeparatorCount = NULL; WCHAR Separator = L';';
ColonCount = std::count(S.begin(), S.end(), L':');
SeparatorCount = std::count(S.begin(), S.end(), Separator);
if ((SS.find(Separator) != std::wstring::npos) || (SeparatorCount > ColonCount))
{
// SEPARATOR NEED TO BE ESCAPED, BUT DON'T KNOW TO DO THIS.
}
if (S.find(SS) != std::wstring::npos)
{
NS = S.substr(S.find(SS) + SS.length() + 1);
if (NS.find(Separator) != std::wstring::npos) { NS = NS.substr(NULL, NS.find(Separator)); }
if (NS[NS.length() - 1] == L']') { NS.pop_back(); }
return NS;
}
return L"";
}
Above function correctly outputs MANGO if I use it like:
ExtractSubStringFromString(L"[VALUE: MANGO; DATA: NOTHING]", L"VALUE")
However, if I have two escape separators in following string, I tried doubling like ;;, but I am still getting MANGO instead ;MANGO;:
ExtractSubStringFromString(L"[VALUE: ;;MANGO;;; DATA: NOTHING]", L"VALUE")
Here, value assigner is colon and separator is semicolon. I want to allow users to pass colons and semicolons to my function by doubling extra ones. Just like we escape double quotes, single quotes and many others in many scripting languages and programming languages, also in parameters in many commands of programs.
I thought hard but couldn't even think a way to do it. Can anyone please help me on this situation?
Thanks in advance.
You should search in the string for ;; and replace it with either a temporary filler char or string which can later be referenced and replaced with the value.
So basically:
1) Search through the string and replace all instances of ;; with \tempFill- It would be best to pick a combination of characters that would be highly unlikely to be in the original string.
2) Parse the string
3) Replace all instances of \tempFill with ;
Note: It would be wise to run an assert on your string to ensure that your \tempFill (or whatever you choose as the filler) is not in the original string to prevent an bug/fault/error. You could use a character such as a \n and make sure there are non in the original string.
Disclaimer:
I can almost guarantee there are cleaner and more efficient ways to do this but this is the simplest way to do it.
First as the substring does not need to be splitted I assume that it does not need to b pre-processed to filter escaped separators.
Then on the main string, the simplest way IMHO is to filter the escaped separators when you search them in the string. Pseudo code (assuming the enclosing [] have been removed):
last_index = begin_of_string
index_of_current_substring = begin_of_string
loop: search a separator starting at last index - if not found exit loop
ok: found one at ix
if char at ix+1 is a separator (meaning with have an escaped separator
remove character at ix from string by copying all characters after it one step to the left
last_index = ix+1
continue loop
else this is a true separator
search a column in [ index_of_current_substring, ix [
if not found: error incorrect string
say found at c
compare key_string with string[index_of_current_substring, c [
if equal - ok we found the key
value is string[ c+2 (skip a space after the colum), ix [
return value - search is finished
else - it is not our key, just continue searching
index_of_current_substring = ix+1
last_index = index_of_current_substring
continue loop
It should now be easy to convert that to C++
I use C++ in QT!!!
I have a string that contains some value that i have to save in a two float's vector.
The values that have to save in the first vector are separate with a ';' character and after a values that have to save in the second vector there is ':' character.
So I need to detect where are the delimiter character and save in the first float's vector the character between ':' and ';' and in the second vector the character between ':' and ';'
Can you help me?
Example of my QString: 10;2:56;12:10;89:
Vector that I would want: first:10,56,10
second:2,12,89
At first you have to split them via .split method of QString, the result of split method is a QStringList object, then you can accessing splited literals with .at(N) method.
After accessing first number group, you have to split them again and finaly accessing each part individually. .at(N) method returns a
QString so you have to convert it to float via .toFloat() method
QString str = "10;2:56;12:10;89:";
QStringList strSplited = str.split(':');
QString numberGroup = strSplited.at(0);
float ac = numberGroup.split(';').at(0).toFloat();
float bc = numberGroup.split(';').at(1).toFloat();
If i have a QString in the form of QString s = QString("A:B[1:2]:C:D"); i want somehow to split by ':', but only, if not enclosed in square-brackets.
So the desited output of the above QString woud be "A", "B[1:2]", "C", "D"
Right now, I can only think of something like replacing ':' in the range of s.indexOf('[') and s.indexOf(']'), then split and afterwards replace back to ':' in any remaining split, but that seems rather inconvenient.
EDIT: based on comments and answers: any number in square-brackets shall be the same after splitting. There are characters, e.g.: ';' that i can use t as temporary replacement for ':'
Any better idea?
Usually, I like the idea of using a regular expression here for split directly, but I could not come up with one quickly. So here it your idea of first replacing the unwanted colon with something else (here a semicolon) and then split on the remaining colons and replace the semicolon back to a colon on the separate strings.
#include <QDebug>
#include <QRegularExpression>
#include <QString>
int main()
{
QString string("A:B[1:2]:C:D");
// This replaces all occurences of "[x:y]" by "[x;y]" with
// x and y being digits.
// \\[ finds exactly the character '['. It has to be masked
// by backslashes because it's a special character in regular
// expressions.
// (\\d) is a capture for a digit that can be used in the
// resulting string as \\1, \\2 and so on.
string = string.replace(QRegularExpression("\\[(\\d):(\\d)\\]"), "[\\1;\\2]");
// split on the remaining colons
QStringList elements = string.split(':');
// Iterate over all fractions the string was split into
foreach(QString element, elements) {
// Replace the semicolons back to colons.
qDebug() << element.replace(QRegularExpression("\\[(\\d);(\\d)\\]"), "[\\1:\\2]");
}
}
The output:
"A"
"B[1:2]"
"C"
"D"
Probably far from optimal but... you could do an initial split on ':' and then post-process the results to coalesce items containing '[' and ']'. So, given your initial string, something like...
QString s("A:B[1:2]:C:D");
QStringList l = s.split(':');
for (int i = 0; i < l.size(); ++i) {
if (l[i].contains('[')) {
l[i] += ":" + l[i +1];
l.takeAt(i + 1);
}
}
This assumes, of course, that any given '[', ']' pair will have at most one intervening ':'.
I will provide my working code as answer, but accept any better idea:
So first i replace any colon inside of square-brackets:
QString ShuntingYard::replaceIndexColons(QString& expression)
{
int index = 0;
while (expression.indexOf('[', index) != -1)
{
int open = expression.indexOf('[', index);
int close = expression.indexOf(']', open);
int colon = expression.indexOf(':', open);
if (colon > open && colon < close)
expression.replace(colon, 1, ';');
index = open + 1;
}
return expression;
}
Then, i can split with splitExpression, this splits by several delimiters, including :
expression = replaceIndexColons(expression);
QStringList list = splitExpression(expression);
Q_FOREACH(QString s, list)
{
s.replace(";", ":");
}
and put it back together...
In my project I need to determine occurrence of the string in the list of strings. The duplicates in the list are not allowed, and the order is irrelevant.
Please help me choose the best Qt container for the string search.
If you want a list of strings, Qt provides the QStringList class.
Once all strings are added, you can call the removeDuplicates function to satisfy your requirement of no duplicates.
To search for a string, call the filter function, which returns a list of strings containing the string, or regular expression passed to the function.
Here's an example, adapted from the Qt documentation: -
// create the list and add strings
QStringList list;
list << "Bill Murray" << "John Doe" << "Bill Clinton";
// Oops...added the same name
list << "John Doe";
// remove any duplicates
list.removeDuplicates();
// search for any strings containing "Bill"
QStringList result;
result = list.filter("Bill");
result is a QStringList containing "Bill Murray" and "Bill Clinton"
If you just want to know if a string is in the list, use the contains function
bool bFound = list.contains("Bill Murray");
Found will return true.