Pregunta

Quiero convertir QStrings en nombres de archivos.Como me gustaría que el nombre del archivo se vea limpio, quiero reemplazar todo lo que no sea letras ni números por un guión bajo.El siguiente código debería hacer eso.

#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;
}

Sin embargo, en mi computadora, esto no funciona, obtengo como resultado:

�_

Buscando una explicación, la depuración me dice que QString("§").size() = 2 > 1 = QString("a").size().

Mis preguntas:

  • ¿Por qué QString usa 2 QChars para "§"?(resuelto)
  • ¿Tienes una solución para makeFilename?¿Funcionaría también para los chinos?
¿Fue útil?

Solución

Además de lo que otros han dicho, tenga en cuenta que un QString es una cadena codificada en UTF-16.Un carácter Unicode que está fuera del BMP requiere 2 QChar valores que trabajan juntos, llamado par sustituto, para codificar ese carácter.El Documentación QString dice tanto:

Los caracteres Unicode con valores de código superiores a 65535 se almacenan utilizando pares sustitutos, es decir, dos QChars consecutivos.

No estás teniendo eso en cuenta al recorrer el QString.Estás mirando cada uno QChar individualmente sin comprobar si pertenece a una pareja sustituta o no.

Pruebe esto en su lugar:

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; 
} 

Otros consejos

OK, aquí está mi teoría: cuando alimenta el literal "§" a un QTRing, QT usa una codificación predeterminada porque no estableció uno.Si su compilador utiliza UTF-8 para almacenar literales de cadena, es posible que le alimenten 2 bytes que se convierten en 2 caracteres en lugar de uno.Del mismo modo, la salida de "toascII" es muy probable que también lo haga lo incorrecto.

Desde el aspecto de él, deberá averiguar qué utiliza su compilador para almacenar literales de cadenas y llame a setcodecforcstrings con el valor correcto.

Editar: Dada su descripción, si no supiera la codificación para mi compilador, probablemente lo intentaría QTextCodec :: CODECFORNAME ("UTF-8") como parámetro a la primera capa: -)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top