Interesting effect with tr().arg()
-
Hi all,
I observed an interesting issue with tr().arg() a minute ago - I do have a work-around but wonder if this is actually a bug. Opinions of course welcome.
Suppose you do the following:
tr("%1%2%3").arg("A").arg("%2A").arg("B")
The expected outcome is "A%2AB", right? Well, the "%" in the second arg() seems to throw the replacement algorithm off, because the actual result is "ABA%3".
My workaround is to put the "%"-containing text as the last arg(), then it works:
tr("%1%3%2").arg("A").arg("B").arg("%2A").
It seem to me that the text in an arg should not affect how the args are treated for tr().
Best,
Chris -
Hi all,
I observed an interesting issue with tr().arg() a minute ago - I do have a work-around but wonder if this is actually a bug. Opinions of course welcome.
Suppose you do the following:
tr("%1%2%3").arg("A").arg("%2A").arg("B")
The expected outcome is "A%2AB", right? Well, the "%" in the second arg() seems to throw the replacement algorithm off, because the actual result is "ABA%3".
My workaround is to put the "%"-containing text as the last arg(), then it works:
tr("%1%3%2").arg("A").arg("B").arg("%2A").
It seem to me that the text in an arg should not affect how the args are treated for tr().
Best,
Chris@ChrisVT
Firstly, I can't see how this can have anything to do withtr()
function. As per http://doc.qt.io/qt-5/qobject.html#tr,QObject::tr()
simply returns aQString
, only then does it evaluate the.arg()
s, so the whole thing is simplyQString::arg()
calls, forget abouttr()
.- Check what plain
tr("%1%2%3")
returns? - Check what
QString("%1%2%3").arg("A").arg("%2A").arg("B")
returns?
- Check what plain
-
Hi,
There's a warning about that in QString's documentation
-
Hi all,
I observed an interesting issue with tr().arg() a minute ago - I do have a work-around but wonder if this is actually a bug. Opinions of course welcome.
Suppose you do the following:
tr("%1%2%3").arg("A").arg("%2A").arg("B")
The expected outcome is "A%2AB", right? Well, the "%" in the second arg() seems to throw the replacement algorithm off, because the actual result is "ABA%3".
My workaround is to put the "%"-containing text as the last arg(), then it works:
tr("%1%3%2").arg("A").arg("B").arg("%2A").
It seem to me that the text in an arg should not affect how the args are treated for tr().
Best,
Chris@ChrisVT Hi,Friend,Welcome.
You can write some test code, to find why. It is interesting.
Do not omit Intermediate results.
You will clear well from following snippet:
#include <QCoreApplication> #include <QtCore/QDebug> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); qDebug() << QObject::tr("%1%2%3"); /// %1%2%3 qDebug() << QObject::tr("%1%2%3").arg("A"); /// A%2%3 qDebug() << QObject::tr("%2%3").arg("A"); ///A%3 qDebug() << QObject::tr("%1%2%3").arg("A").arg("%2A"); /// A%2A%3 qDebug() << QObject::tr("%1%2%3").arg("A").arg("%2A").arg("B"); /// ABA%3 // To replace First %, is %1=>A, result is tr(A%2%3).arg(%2A).arg(B) // In Result To replace First %, is %2=>%2, result is (A%2A%3).arg(B) // In Result To replace First %, is %2=>B, result is ABA%3 return a.exec(); }
-
I discussed in the past this and also the season why you should only use
arg(QString)
and not the other overloads -
@ChrisVT Hi,Friend,Welcome.
You can write some test code, to find why. It is interesting.
Do not omit Intermediate results.
You will clear well from following snippet:
#include <QCoreApplication> #include <QtCore/QDebug> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); qDebug() << QObject::tr("%1%2%3"); /// %1%2%3 qDebug() << QObject::tr("%1%2%3").arg("A"); /// A%2%3 qDebug() << QObject::tr("%2%3").arg("A"); ///A%3 qDebug() << QObject::tr("%1%2%3").arg("A").arg("%2A"); /// A%2A%3 qDebug() << QObject::tr("%1%2%3").arg("A").arg("%2A").arg("B"); /// ABA%3 // To replace First %, is %1=>A, result is tr(A%2%3).arg(%2A).arg(B) // In Result To replace First %, is %2=>%2, result is (A%2A%3).arg(B) // In Result To replace First %, is %2=>B, result is ABA%3 return a.exec(); }
@joeQ
I still don't get how this behaviour is anything to do with usingQObject::tr()
, in your examples and this thread title? I can't test because I don't use C++, but wouldn't your examples behave just the same if you usedQString
in place ofQObject::tr
? Thearg()
s are evaluated after thetr()
, not before, aren't they? -
Further to what I have written above, and to @VRonin 's post:
ISTM that you should never use
qString.arg().arg()
. The chainedarg
s, which work on the substituted result from the previousarg()
calls, are far too dangerous. [You wouldn't use C'ssprint(format)
with a non-literal format string for the same kind of reason, would you?]Like with
sprintf
, or repeatedreplace
s or regular expression substitutions, you can only afford to use a substituter which works from a single, original string specifying what to do, not one affected by a previous substitution. You need a function which does multiple substitutions at the same time, not one after the other, to be safe.So I don't see/where is Qt's
QString::argList()
function, so you can go like:QString("%1%2%3")::argList(arg1, arg2, arg3)
, which is what you need to do? -
@ChrisVT
Firstly, I can't see how this can have anything to do withtr()
function. As per http://doc.qt.io/qt-5/qobject.html#tr,QObject::tr()
simply returns aQString
, only then does it evaluate the.arg()
s, so the whole thing is simplyQString::arg()
calls, forget abouttr()
.- Check what plain
tr("%1%2%3")
returns? - Check what
QString("%1%2%3").arg("A").arg("%2A").arg("B")
returns?
- Check what plain
-
Further to what I have written above, and to @VRonin 's post:
ISTM that you should never use
qString.arg().arg()
. The chainedarg
s, which work on the substituted result from the previousarg()
calls, are far too dangerous. [You wouldn't use C'ssprint(format)
with a non-literal format string for the same kind of reason, would you?]Like with
sprintf
, or repeatedreplace
s or regular expression substitutions, you can only afford to use a substituter which works from a single, original string specifying what to do, not one affected by a previous substitution. You need a function which does multiple substitutions at the same time, not one after the other, to be safe.So I don't see/where is Qt's
QString::argList()
function, so you can go like:QString("%1%2%3")::argList(arg1, arg2, arg3)
, which is what you need to do?@JonB said in Interesting effect with tr().arg():
You need a function which does multiple substitutions at the same time, not one after the other, to be safe.
ππππππππ
@JonB said in Interesting effect with tr().arg():
which is what you need to do?
Actually it's very easy to solve the problem at hand:
tr("%1%2%3").arg(QStringLiteral("A"),QStringLiteral("%2A"),QStringLiteral("B"))
-
@JonB said in Interesting effect with tr().arg():
You need a function which does multiple substitutions at the same time, not one after the other, to be safe.
ππππππππ
@JonB said in Interesting effect with tr().arg():
which is what you need to do?
Actually it's very easy to solve the problem at hand:
tr("%1%2%3").arg(QStringLiteral("A"),QStringLiteral("%2A"),QStringLiteral("B"))
-
Yes, up to 9: http://doc.qt.io/qt-5/qstring.html#arg-21
-
Yes, up to 9: http://doc.qt.io/qt-5/qstring.html#arg-21
-
I discussed in the past this and also the season why you should only use
arg(QString)
and not the other overloadsThanks for all the responses - very insightful!
@VRonin This also happens with QStrings:
qDebug() << QString("%1%2%3").arg("A").arg("%2A").arg("B"); -> "ABA%3"
qDebug() << QString("%1%2%3").arg(QString("A")).arg(QString("%2A")).arg(QString("B")); -> "ABA%3"
But yes, implicit type conversion can be very hard to figure out. Been there!@joeB Good advice about using the arglist instead, but
(a) this only works for QStrings, not for numerical formats, and
(b) Qt offers the ability to use chained args which MOSTLY work.
I was incorrectly assuming that arg(a).arg(b) should be the same as .arg(a,b) for constant QStrings a and b. I'll still say it's not all that intuitive that it isn't. -
Thanks for all the responses - very insightful!
@VRonin This also happens with QStrings:
qDebug() << QString("%1%2%3").arg("A").arg("%2A").arg("B"); -> "ABA%3"
qDebug() << QString("%1%2%3").arg(QString("A")).arg(QString("%2A")).arg(QString("B")); -> "ABA%3"
But yes, implicit type conversion can be very hard to figure out. Been there!@joeB Good advice about using the arglist instead, but
(a) this only works for QStrings, not for numerical formats, and
(b) Qt offers the ability to use chained args which MOSTLY work.
I was incorrectly assuming that arg(a).arg(b) should be the same as .arg(a,b) for constant QStrings a and b. I'll still say it's not all that intuitive that it isn't.@ChrisVT
I love things which "MOSTLY" work :)Be aware, if you are going to use "numerical formats" as you say then, as @VRonin pointed out in the post he referred to, these will not be localed. If you care about that, you must format them to localed strings in the first place, then you can pass them to the list-
arg()
because they are now strings.