QChar :: isLetterOrNumber () завершается ошибкой

Я хочу конвертировать 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 QChars для «§»? (решена)
  • У вас есть решение для makeFilename? Будет ли это также работать для китайцев?

0

Решение

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

Символы Unicode со значениями кода выше 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;
}
1

Другие решения

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

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

РЕДАКТИРОВАТЬ: учитывая ваше описание, если бы я не знал кодировку для моего компилятора, я бы, вероятно, сначала попробовал QTextCodec :: codecForName («UTF-8») в качестве параметра для setCodec 🙂

1

По вопросам рекламы [email protected]