为什么QString无法传递格式的QRegExp(“[\\ x00 - \\ xff] *”)?

时间:2014-04-03 13:04:23

标签: regex qt qregexp

我的QRegExp具有以下模式

QRegExp byteArray;
byteArray.setPattern("[\\x00-\\xff]*");

这种模式用于验证QString。 有人可以举例说明哪种QString不能通过上述模式的测试?我有一个错误,其中有一个与模式不匹配的QString。

Cand这个模式匹配任何Unicode字符串?

未通过模式验证的QString示例:HÈńr

为什么?

2 个答案:

答案 0 :(得分:3)

QString在内部使用UTF-16,而不是UTF-8。

您还需要以\ x0001开头的QRegExp。

int main()
{
        uint data[] = { 0x10c436, 0 };
        QString s = QString::fromUcs4(data);
        QRegExp r("^[\\x0001-\\xffff]+$");
        qDebug() << s.size() << s.contains(r);
}

将导致匹配,

2 true

注意:如果您使用的是QRegularExpression,则上述内容将不再匹配。 QRegularExpression使用pcre UTF16,因此必须在PCRE代码中进行一些花哨的检查,尽管它没有报告任何错误。我没有进一步研究它。

此外,QRegularExpression接受\ x0000,但QRegExp不接受。

故事的道德是不要试图将二进制数据与正则表达式匹配。

答案 1 :(得分:2)

您在模式中提供的数字是UTF-16代码单位值(与代码点不同)。请参阅the Unicode Glossay以供参考。如果您将“HÈńr”粘贴到unicodelookup.com,您会注意到'ń'的Unicode代码点为0x144,大于0xFF,您指定为可接受范围的上限。

要接受所有Unicode字符,您需要以下表达式:

[\x0-\xFFFF]*

要仅接受第一个平面字符 - 一个代码单元(QChar)始终对应于一个代码点的字符,您需要以下表达式:

[\x0-\xD7FF\xE000-\xFFFF]*

您对正则表达式赋予的名称byteArray完全具有欺骗性:QString不是字节数组,不是Unicode代码点数组,而是UTF-16代码数组单元。

第一个平面中的代码点(U + 0000到U + D7FF和U + E000到U + FFFF)以UTF-16表示为单个代码单元。 QChar始终是代码单元。来自其他辅助平面的代码点表示为两个QChar代码单元 - 代理对。

处理此类配对会使问题复杂化。假设你想匹配'',代码点0x10398。这表示为UTF-16中的两个代码单元:0xD800 0xDF98。模式将是:

([\xD800][\xDF98])
#include <QString>
#include <QDebug>
#include <QRegExp>
int main()
{
   uint data[] = { 0x10398, 0 };
   QString s = QString::fromUcs4(data);
   QRegExp r("^([\\xD800][\\xDF98])$");
   qDebug() << s.size() << s.contains(r);
}

输出结果为:

2 true

如果您只想匹配某些范围,比如说第一个平面和storied Linear-B Syllabary 范围是10000-1007F,您可以使用以下模式:

([\x0-\xD7FF\xE000-\xFFFF]|([\xD800][\xDC00-\xDC7F]))*
int main()
{
   uint data[] = { 0x30, 0x40, 0x10000, 0x1007F, 0 };
   QString s = QString::fromUcs4(data);
   QRegExp r("^([\\x0-\\xD7FF\\xE000-\\xFFFF]|([\\xD800][\\xDC00-\\xDC7F]))+$");
   qDebug() << s.size() << s.contains(r);
}

输出结果为:

6 true