Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Solving QT's QString arg() ambiguity

There is an issue using QString::arg() when a string contains a digit right after a place marker. It's not clear from the QString::arg() function description what would happen in case of such a replacement:

QString("String for replacement %1234").arg("blah");

Will this result in "String for replacement blah234" or "String for replacement blah34"?

I looked in the QT's source code to answer this question. It seems that the algorithm which looks for place markers is 'greedy' and it would take both digits in the example above.

Here is the source of the QT's function which is used inside the QString::arg() (QT 4.8.4):

static ArgEscapeData findArgEscapes(const QString &s)
{
const QChar *uc_begin = s.unicode();
const QChar *uc_end = uc_begin + s.length();

ArgEscapeData d;

d.min_escape = INT_MAX;
d.occurrences = 0;
d.escape_len = 0;
d.locale_occurrences = 0;

const QChar *c = uc_begin;
while (c != uc_end) {
    while (c != uc_end && c->unicode() != '%')
        ++c;

    if (c == uc_end)
        break;
    const QChar *escape_start = c;
    if (++c == uc_end)
        break;

    bool locale_arg = false;
    if (c->unicode() == 'L') {
        locale_arg = true;
        if (++c == uc_end)
            break;
    }

    if (c->digitValue() == -1)
        continue;

    int escape = c->digitValue();
    ++c;

    if (c != uc_end && c->digitValue() != -1) {
        escape = (10 * escape) + c->digitValue();
        ++c;
    }

    if (escape > d.min_escape)
        continue;

    if (escape < d.min_escape) {
        d.min_escape = escape;
        d.occurrences = 0;
        d.escape_len = 0;
        d.locale_occurrences = 0;
    }

    ++d.occurrences;
    if (locale_arg)
        ++d.locale_occurrences;
    d.escape_len += c - escape_start;
}
return d;
}

Is there a better way of solving such an ambiguity than always using a 2-digit place markers?

like image 729
Oleg Yakovenko Avatar asked May 24 '13 14:05

Oleg Yakovenko


2 Answers

Since you can only use %1 to %99 as markers and you can skip marker numbers you can write:

QString("String for replacement %10234").arg("blah");

to output String for replacement blah234

like image 96
Frank Avatar answered Nov 14 '22 17:11

Frank


Qt help states for arg(const QString & a, int fieldWidth = 0, QChar fillChar = QLatin1Char( ' ' ))

Returns a copy of this string with the lowest numbered place marker replaced by string a, i.e., %1, %2, ..., %99.

...

Place marker numbers must be in the range 1 to 99.

Therefore, what you're seeing is, by definition, correct; the first two numbers will be replaced. If you're wanting "String for replacement blah234", then you could define the string as: -

QString("String for replacement %1%2").arg("blah").arg(234);
like image 4
TheDarkKnight Avatar answered Nov 14 '22 15:11

TheDarkKnight