c++ - QChar::isLetterOrNumber() 失败

标签 c++ string unicode qstring qchar

我想将 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/

相关文章:

java - 如何将给定的字符串转换为回文?

Python检查字符串是否包含字典键

python - 当字符位于 unicode 范围内时,如何用空格填充字符?

php - 验证 unicode 文本区域的最小长度

python - 在 Python 中匹配 Unicode 字边界

使用控制台窗口进行 C++/SDL 调试

c++ - 刷新 QGraphicsScene/QGraphicsView

c++ - 在较大字符串中查找子字符串的查找方法

c++ - 线程池,C++

c++ - 在构造函数的初始化列表上初始化数组或 vector