How to deal with "%1" in the argument of QString::arg()?
Asked Answered
M

3

42

Everybody loves

QString("Put something here %1 and here %2")
    .arg(replacement1)
    .arg(replacement2);

but things get itchy as soon as you have the faintest chance that replacement1 actually contains %1 or even %2 anywhere. Then, the second QString::arg() will replace only the re-introduced %1 or both %2 occurrences. Anyway, you won't get the literal "%1" that you probably intended.

Is there any standard trick to overcome this?

If you need an example to play with, take this

#include <QCoreApplication>
#include <QDebug>

int main()
{
    qDebug() << QString("%1-%2").arg("%1").arg("foo");
    return 0;
}

This will output

"foo-%2"

instead of

"%1-foo"

as might be expected (not).

    qDebug() << QString("%1-%2").arg("%2").arg("foo");

gives

"foo-foo"

and

    qDebug() << QString("%1-%2").arg("%3").arg("foo");

gives

"%3-foo"
Michal answered 9/3, 2011 at 17:19 Comment(3)
I know, I could just use string concatenation using operator + () but in some places, e.g. translation using tr(), one would like to keep the ability to reorder the arguments in the template.Michal
Wow! I never encountered that case, but if a translation is the string "%1" (opposed to 1%, for example) then it won't work right at all. This really does not make sense. It looks like they reapply the arguments to the result over and over.Fairspoken
Wasn't there the possibility to pseudo-escape "%1" by writing "%%1"? Still the functionality of using a percent-marker in an arg-call is good. Imagine you have a standard error-string using %1 to replace the "where" and %2 to replace "what" - now in some cases you simply replace "where" with a string, in others you'd like a number. In case of the string you'd maybe want to put apostrophes around it, in case of a number a hashtag in front would be good to improve readability. Now you can use the 1st arg-call to replace %1 with f.e. "#%3" and a 3rd arg-call to insert the number.Dangle
S
35

See the Qt docs about QString::arg():

QString str;
str = "%1 %2";
str.arg("%1f", "Hello"); // returns "%1f Hello"
Stagnant answered 9/3, 2011 at 17:30 Comment(5)
Ok, thanks! And how to deal with the case that you need different overloads of QString::arg(), e.g. for numbers as well? Using QString::number() in the multi-QString-arg() is not the same thing as it doesn't give you the possibility to specify the field width.Michal
Ok, I could use QString::leftJustified() or QString::rightJustified(), but this gets lengthy. I think having an automatically escaping version of arg() would be great.Michal
@Johnny, QString("%1-%2").arg("%1").arg(23, 8, 10, QChar('0')); will make QString("00000023-%2") instead of QString("%1-00000023").Michal
@Tilman, what do you think about this: QString("%1-%2").arg("%1", QString("%1").arg(23, 8, 10, QChar('0'))); ?Stagnant
@Johnny, yeah, not totally terrible ;-) Still sad, it doesn't work in the original elegance... One way would be to escape all % in substitutions and replace them back once the arg() shower has stopped, using some intermediate string-template class. Thanks for your thoughts!Michal
L
11

Note that the arg() overload for multiple arguments only takes QString. In case not all the arguments are QStrings, you could change the order of the placeholders in the format string:

QString("1%1 2%2 3%3 4%4").arg(int1).arg(string2).arg(string3).arg(int4);

becomes

QString("1%1 2%3 3%4 4%2").arg(int1).arg(int4).arg(string2, string3);

That way, everything that is not a string is replaced first, and then all the strings are replaced at the same time.

Lilongwe answered 15/9, 2017 at 7:10 Comment(0)
I
4

You should try using

QString("%1-%2").arg("%2","foo");
Ideatum answered 7/7, 2015 at 14:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.