[SOLVED] String formating %1%2 vs %2%1

  • I've encountered a strange issue while formatting QString.

    A very simplified description:
    format string was %2%1
    arg 1 was int (e.g. 1)
    arg 2 was QString (e.g. D)
    the result was "D" - the integer went missing

    When swapped the 2 params it formatted correctly.
    I use 4.8.1
    Is anyone aware of this issue?

  • (QString("%1/%2").arg(intero).arg(licenza));

    intero is a qint16, and licenza is a qstring;

  • Hi Salvatelo

    I know the syntax.

    If I use your case: (!I have not tested this specific code, just a concept)
    a) OK: QString(”%1%2”).arg(intero).arg(licenza)
    b) Fails: QString(”%2%1”).arg(licenza).arg(intero)
    Theoretically, this should give the same result. Correct?
    Note: There is no whitespave or any symbol between the two placeholders.
    In case I inserted a space between %2 & %1 case B would work.

  • @ qint16 a=3;

    the result is 3 / licenza;

    @ qint16 a=3;

    the result is 3 / licenza;

  • There is a misunderstanding.

    There is no space or any other symbol between %2 and %1 - "%2%1"

  • I did not understand

  • As I'll have a few minutes of time I'll make minimalistic source to reproduce this

  • Could you paste your code exactly as it is?

  • Frankie

    I'll put together a simple code to reproduce the issue on a smaller scale.

  • Hi gkavrecic,

    its because arg looks for the smallest place marker, like %1, %2 ... if you replace the first marker with a digit, e. g. 3 it will find the next marker as # and arg will replace the marker (#) with "D".

    best regards

    PS: why was the rest of my post missing?

  • So, this means that the markers (when concatenated) have to be in ascending order?

    Is this described anywhere?

  • Hm, whats wrong with the forum? % 23 gets replaced with #??

    Look here: http://qt-project.org/doc/qt-4.8/qstring.html#arg

  • Nothing wrong with the forum.

    According to docs (also your link):
    ...each arg() will still replace the lowest numbered unreplaced place marker, no matter where it appears...

    According to my experience this is not true.

    I'm going to write the test appl now.
    I still might find my bug doing it...

  • Yeah, if you replace the first occurence in %2%1 with a digit the new marker will be %2x, where x is the digit. So the new smallest marker is 21, 22 depending on what digit x has been.

  • ok, here is the minimalistic appl to prove this.

    @#include <QtCore/QCoreApplication>
    #include <QDebug>

    int main(int argc, char *argv[])
    int i = 7;
    QString s = "D";

    QString a = QString("%1%2").arg(s).arg(i,-2);
    QString b = QString("%2%1").arg(i,-2).arg(s);
    qDebug() << a;
    qDebug() << b;
    return 0;


    The output of this code is (copy/pasted from the console window):
    @"D7 "
    "D "@

  • Its working as expected, just try it this way:

    @ QString b = QString("%2%1").arg(i,-2);
    qDebug() << b; // = "% 27"
    b = b.arg(s); // now arg finds 27 as smalles marker and will replace it
    qDebug() << b;@

  • Saugglocke,
    I was just thinking this before I refreshed the page...
    It seems it has a very simplistic logic while converting it - after each argument it reuses the new string.

    But with this logic one can't, for example, internationalise some monetary value like 5€ or $8 using the logic to switch places to value and currency...

    You come back to position aware programming as it is in sprintf...
    Not all the way, but still. You can't describe it as no matter where it appears

  • a reply to your sample code.
    It does not work.

    • the intermediate result is "%27 "

    • the final one is "D " - same as before, just need more code

  • args return value is a new string, hence the next arg will use the copy.

    The sample was just to show the logic behind arg. It won't solve the problem. You could add a space character and replace it afterwards:

    @QString b = QString("%2 %1").arg(i,-2).arg(s);
    qDebug() << b.replace(" ", "");@

  • @ QString a = QString("%1%2").arg(s).arg(i,-2);@
    is a correct form.

    @ QString b = QString("%2%1").arg(i,-2).arg(s);@
    not a correct form.

    %1 must precede %2.
    you can change the order of arg bat not the order of %n.

  • Saugglocke & Salvatello
    I understand what you want to say. And I solved my issues before I started to write this thread. I've just reordered the args as they appear in the string. I could solve it using sprintf the same way. For me is also easier to format the output with sprintf as it is easier and more logical.

    The second form of Salvatello is not wrong. In my opinion the library works wrong.

    I just wanted to check and put forward that the whole concept no matter where it appears falls as it can't be used as described. I can't really rely that the transtlatted string will work as expected.

  • I see what you're saying but I don't see how every separate call to .arg() with the single parameter could consider the case of the string replacement you describe here (the creation of & for example, which really reads as the 26th argument).

    Maybe what you should have done (or did already) is use the overload that replaces the strings in one pass?

    QString QString::arg(const QString & a1, const QString & a2) const

    bq. This is the same as str.arg(a1).arg(a2), except that the strings a1 and a2 are replaced in one pass. This can make a difference if a1 contains e.g. %1

    Anyway, if you got to this or another solution, please post it and edit the post title to [SOLVED].

  • Hi Frankie,

    I have not. But seems the only way to make it work correctly.

Log in to reply