我有具有以下模式的 QRegExp
QRegExp byteArray;
byteArray.setPattern("[\\x00-\\xff]*");
这是用于验证QString
的模式。有人可以举例说明哪种QString
' 不能通过上述模式的测试吗?我有一个错误,其中有一个与模式不匹配的 QString。
这个模式可以匹配任何 Unicode 字符串吗?
未通过模式验证的 QString 示例:HÈńr
为什么?
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 不接受。
故事的寓意是不要尝试将二进制数据与正则表达式匹配。
您在模式中给出的数字是 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