我想将 QString 转换成文件名。因为我希望文件名看起来干净,所以我想用下划线替换所有非字母和非数字。以下代码应该可以做到这一点。
#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
的解决方案吗?它也适用于中国人吗?
最佳答案
除了其他人所说的,请记住 QString
是 UTF-16 编码的字符串。 BMP 之外的 Unicode 字符需要 2 个一起工作的 QChar
值,称为代理对,以便对该字符进行编码。 QString documentation说了这么多:
Unicode characters with code values above 65535 are stored using surrogate pairs, i.e., two consecutive QChars.
在遍历 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;
}
关于c++ - QChar::isLetterOrNumber() 失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12710528/