0

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?

tobilocker
  • 891
  • 8
  • 27

3 Answers3

2

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"
  • But then the information of the digits will be lost forever. I need a Solution that keeps the digits as they are. – tobilocker May 30 '16 at 14:29
  • The digits are kept. I will update my answer, though. :) –  May 30 '16 at 14:32
  • This takes any digit in the range `[0-9]` but the output will always be `[1:2]` – tobilocker May 30 '16 at 14:37
  • @tobilocker: \\1 and \\2 are the contents of the captures from the regular expression. So it outputs the correctly used digits here if I replace the original `[1:2]` by `[4:8]`. –  May 30 '16 at 14:56
  • OK i will test that now. Thanks :) – tobilocker May 30 '16 at 14:59
  • Simplified the expression a little bit. The range of possible characters [0-9] can be expressed as \\d. –  May 30 '16 at 17:57
  • Thing like `QRegExp(R"([\]:]*(\[\d+:\d+\])?)").indexIn(str, pos)` allows to iterate on valid element and avoid the trick to replace `:` by `;`. (and using raw string are very good in particular for regExp). – Jarod42 May 30 '16 at 21:33
  • @Jarod42: The raw string advice is nice. I am trying to use your regexp though and am failing to understand the intention of it. What is the `[\]:]` good for? –  May 30 '16 at 23:08
  • Some typos indeed, missing `^` and `]` instead of `[`, any character which is not `[` nor `:` : `[:\[]`. – Jarod42 May 30 '16 at 23:59
0

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 ':'.

G.M.
  • 12,232
  • 2
  • 15
  • 18
0

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...

tobilocker
  • 891
  • 8
  • 27
  • So you expect no `;` in your original `QString` – Jarod42 May 30 '16 at 14:38
  • Yes - or lets say there are limitations, since the string is an arithmetic expression, mixed with ternary conditionals and array indexes. Thats where `?:` collides with `[start:end]` – tobilocker May 30 '16 at 14:43