QRegularExpressionValidator与负前瞻正则不生效问题求助
QRegularExpressionValidator返回Intermediate而非Invalid的原因及解决方案
问题原因
QRegularExpressionValidator的核心设计目标是支持实时输入验证,它的validate方法并非执行严格的全字符串匹配:
- 只要当前输入的内容是某个合法字符串的前缀,就会返回
Intermediate状态,允许用户继续输入(比如用户正在输入过程中,还没完成合法字符串的输入)。 - 只有当输入内容完全不可能扩展为任何合法字符串时,才会返回
Invalid;完全匹配正则时返回Acceptable。
你的测试字符串"0.123456789"包含10个数字(整数位1个+小数位9个),虽然违反了正则中(?!(?:[.,]?\d){10,})的位数限制,但Qt验证器并未直接返回Invalid——它认为用户可能删除最后一个数字,将其修正为合法字符串,因此判定为Intermediate。这和在线正则验证器的全匹配校验逻辑完全不同。
解决方案
要实现严格的校验(完全符合规则返回Acceptable,超出位数直接返回Invalid),可以采用以下两种方式:
方式1:自定义严格验证器
继承QRegularExpressionValidator,重写validate方法,在原有逻辑基础上增加全匹配检查和位数判断:
#include <QRegularExpressionValidator> #include <QRegularExpressionMatch> class StrictRegexValidator : public QRegularExpressionValidator { public: using QRegularExpressionValidator::QRegularExpressionValidator; State validate(QString &input, int &pos) const override { State baseState = QRegularExpressionValidator::validate(input, pos); // 对Intermediate状态的输入做额外检查 if (baseState == Intermediate) { // 检查是否完全匹配正则 QRegularExpressionMatch fullMatch = regularExpression().match(input, 0, QRegularExpression::FullMatch); if (fullMatch.hasMatch()) { return Acceptable; } // 统计数字个数,超过9位直接判定为Invalid int digitCount = input.count(QRegularExpression("[0-9]")); if (digitCount >= 10) { return Invalid; } } return baseState; } };
使用示例:
QString regex = "^[-+]?(?!0\\d)(?!(?:[.,]?\\d){10,})\\d*[.,]?\\d+"; auto validator = new StrictRegexValidator(QRegularExpression(regex)); QString test("0.123456789"); QString test2("+0.1234567"); int pos = 0; auto testStatus = validator->validate(test, pos); // 返回Invalid auto test2Status = validator->validate(test2, pos); // 返回Acceptable
方式2:直接使用全匹配校验
如果不需要实时输入的前缀验证,直接用QRegularExpression::match执行全字符串匹配:
QString regex = "^[-+]?(?!0\\d)(?!(?:[.,]?\\d){10,})\\d*[.,]?\\d+$"; // 增加$确保全匹配 QRegularExpression re(regex); // 测试用例 QString test("0.123456789"); bool testValid = re.match(test).hasMatch(); // false QString test2("+0.1234567"); bool test2Valid = re.match(test2).hasMatch(); // true
注意这里给正则添加了$结尾锚点,强制要求匹配整个字符串,确保校验结果和在线验证器一致。
补充说明
原正则中的(?!0\d)是为了禁止前导零(如"0123"这类字符串),但"0.123"是合法的——因为0后紧跟的是小数点而非数字,符合前瞻断言的限制。
内容的提问来源于stack exchange,提问作者CRaNkXD
相关产品推荐
相关产品推荐

