Вопрос

Я хочу преобразовать QStrings в имена файлов.Поскольку я хочу, чтобы имя файла выглядело чистым, я хочу заменить все небуквы и цифры подчеркиванием.Следующий код должен сделать это.

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

Однако на моем компьютере это не работает, на выходе получаю:

�_

В поисках объяснения отладка сообщает мне, что QString("§").size() = 2 > 1 = QString("a").size().

Мои вопросы:

  • Почему QString использует 2 QChar для «§»?(решено)
  • У вас есть решение для makeFilename?Будет ли это работать и для китайцев?
Это было полезно?

Решение

В дополнение к тому, что сказали другие, имейте в виду, что QString представляет собой строку в кодировке UTF-16.Для символа Юникода, находящегося за пределами BMP, требуется 2 QChar значения, работающие вместе, называемые суррогатной парой, для кодирования этого символа.А Документация по QString говорит так:

Символы Юникода со значениями кодов выше 65535 сохраняются с использованием суррогатных пар, то есть двух последовательных символов QChar.

Вы не учитываете это при проходе через QString.Вы смотрите на каждого QChar индивидуально, не проверяя, принадлежит ли он суррогатной паре или нет.

Вместо этого попробуйте это:

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

Другие советы

Хорошо, вот моя теория: при кормлении буквальной буквы «§ §» к QString, Qt использует некоторую кодировку по умолчанию, потому что вы не установили.Если ваш компилятор использует UTF-8 для хранения строковых литералов, вы можете кормить его 2 байта, которые преобразуются на 2 символа вместо одного.Точно так же ваш вывод «Toascii», скорее всего, тоже не делает неправильные вещи.

Из внешнего вида, вам придется выяснить, что ваш компилятор использует для хранения строковых литералов, и вызов SetCodecForcstrings с правильным значением.

Редактировать: Учитывая ваше описание, если я не знал кодировку для моего компилятора, я бы, вероятно, попробую QtextCodec :: CodeCForname («UTF-8») в качестве параметра на SetCodec First: -)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top