Frage

Ich möchte QStrings in Dateinamen konvertieren.Da ich möchte, dass der Dateiname sauber aussieht, möchte ich alle Nicht-Buchstaben und Nicht-Zahlen durch einen Unterstrich ersetzen.Der folgende Code sollte das tun.

#include <iostream>
#include <QString>

QString makeFilename(const QString& title)
{
    QString result;
    for(QString::const_iterator itr = title.begin(); itr != title.end(); itr++)
     result.push_back(itr->isLetterOrNumber()?itr->toLower():'_');
    return result;
}

int main()
{
    QString str = "§";
    std::cout << makeFilename(str).toAscii().data() << std::endl;
}

Auf meinem Computer funktioniert das jedoch nicht, ich erhalte als Ausgabe:

�_

Auf der Suche nach einer Erklärung sagt mir das Debuggen das QString("§").size() = 2 > 1 = QString("a").size().

Meine Fragen:

  • Warum verwendet QString 2 QChars für „§“?(gelöst)
  • Haben Sie eine Lösung für? makeFilename?Würde es auch für Chinesen funktionieren?
War es hilfreich?

Lösung

Denken Sie zusätzlich zu dem, was andere gesagt haben, daran, dass a QString ist eine UTF-16-codierte Zeichenfolge.Für ein Unicode-Zeichen außerhalb des BMP ist 2 erforderlich QChar Werte, die zusammenarbeiten, ein sogenanntes Ersatzpaar, um dieses Zeichen zu kodieren.Der QString-Dokumentation sagt so viel:

Unicode-Zeichen mit Codewerten über 65535 werden mithilfe von Ersatzpaaren gespeichert, d. h. zwei aufeinanderfolgenden QChars.

Sie berücksichtigen dies nicht, wenn Sie die Schleife durchlaufen QString.Du siehst jeden an QChar einzeln, ohne zu prüfen, ob es zu einem Ersatzpaar gehört oder nicht.

Versuchen Sie stattdessen Folgendes:

QString makeFilename(const QString& title) 
{ 
    QString result; 

    QString::const_iterator itr = title.begin();
    QString::const_iterator end = title.end();

    while (itr != end)
    {
        if (!itr->isHighSurrogate())
        {
            if (itr->isLetterOrNumber())
            {
                result.push_back(itr->toLower()); 
                ++itr;
                continue;
            }
        }
        else
        {
            ++itr;
            if (itr == end)
                break; // error - missing low surrogate

            if (!itr->isLowSurrogate())
                break; // error - not a low surrogate

            /*
            letters/numbers should not need to be surrogated,
            but if you want to check for that then you can use
            QChar::surrogateToUcs4() and QChar::category() to
            check if the surrogate pair represents a Unicode
            letter/number codepoint...

            uint ch = QChar::surrogateToUcs4(*(itr-1), *itr);
            QChar::Category cat = QChar::category(ch);
            if (
                ((cat >= QChar::Number_DecimalDigit) && (cat <= QChar::Number_Other)) ||
                ((cat >= QChar::Letter_Uppercase) && (cat <= QChar::Letter_Other))
                )
            {
                result.push_back(QChar(ch).toLower()); 
                ++itr;
                continue;
            }
            */
        }

        result.push_back('_');
        ++itr; 
    }

    return result; 
} 

Andere Tipps

Ok, hier ist meine Theorie:Wenn Sie das „§“-Literal einem QString zuführen, verwendet Qt eine Standardcodierung, da Sie keine festgelegt haben.Wenn Ihr Compiler UTF-8 zum Speichern von Zeichenfolgenliteralen verwendet, geben Sie ihm möglicherweise 2 Bytes zu, die in 2 Zeichen statt in eines umgewandelt werden.Ebenso macht Ihre „toAscii“-Ausgabe höchstwahrscheinlich auch das Falsche.

So wie es aussieht, müssen Sie herausfinden, was Ihr Compiler zum Speichern und Aufrufen von Zeichenfolgenliteralen verwendet setCodecForCStrings mit dem richtigen Wert.

BEARBEITEN:Wenn ich angesichts Ihrer Beschreibung die Codierung für meinen Compiler nicht wüsste, würde ich wahrscheinlich zuerst QTextCodec::codecForName("UTF-8") als Parameter für setCodec ausprobieren :-)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top