2

我有具有以下模式的 QRegExp

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

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

这个模式可以匹配任何 Unicode 字符串吗?

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

为什么?

4

2 回答 2

3

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

对于 QRegExp,您还需要从 \x0001 开始。

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 不接受。

故事的寓意是不要尝试将二进制数据与正则表达式匹配。

于 2014-04-03T16:13:18.020 回答
3

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

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

[\x0-\xFFFF]*

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

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

byteArray您给正则表达式起的名字完全是骗人的:aQString不是字节数组,也不是 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

如果您只想匹配某些范围,例如第一个平面和传说中的线性 B 音节范围从 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
于 2014-04-03T16:13:29.250 回答