Introduce QRegularExpressionValidator

QRegularExpression counterpart for QRegExpValidator.

Change-Id: Ib391e73dd49e32aeb9b48e6f2217b67a17a83a11
Reviewed-by: David Faure <david.faure@kdab.com>
Reviewed-by: Gunnar Sletta <gunnar.sletta@digia.com>
This commit is contained in:
Giuseppe D'Angelo 2012-03-15 09:02:19 +00:00 committed by The Qt Project
parent ca2f44680c
commit 2d8910cbed
7 changed files with 356 additions and 0 deletions

View File

@ -133,3 +133,46 @@ s = "README.1ST"; v.validate(s, pos); // Returns Acceptable
s = "read me.txt"; v.validate(s, pos); // Returns Invalid
s = "readm"; v.validate(s, pos); // Returns Intermediate
//! [4]
//! [5]
// regexp: optional '-' followed by between 1 and 3 digits
QRegularExpression rx("-?\\d{1,3}");
QValidator *validator = new QRegularExpressionValidator(rx, this);
QLineEdit *edit = new QLineEdit(this);
edit->setValidator(validator);
//! [5]
//! [6]
// integers 1 to 9999
QRegularExpression re("[1-9]\\d{0,3}");
// the validator treats the regexp as "^[1-9]\\d{0,3}$"
QRegularExpressionValidator v(re, 0);
QString s;
int pos = 0;
s = "0"; v.validate(s, pos); // returns Invalid
s = "12345"; v.validate(s, pos); // returns Invalid
s = "1"; v.validate(s, pos); // returns Acceptable
re.setPattern("\\S+"); // one or more non-whitespace characters
v.setRegularExpression(re);
s = "myfile.txt"; v.validate(s, pos); // Returns Acceptable
s = "my file.txt"; v.validate(s, pos); // Returns Invalid
// A, B or C followed by exactly five digits followed by W, X, Y or Z
re.setPattern("[A-C]\\d{5}[W-Z]");
v.setRegularExpression(re);
s = "a12345Z"; v.validate(s, pos); // Returns Invalid
s = "A12345Z"; v.validate(s, pos); // Returns Acceptable
s = "B12"; v.validate(s, pos); // Returns Intermediate
// match most 'readme' files
re.setPattern("read\\S?me(\.(txt|asc|1st))?");
re.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
v.setRegularExpression(re);
s = "readme"; v.validate(s, pos); // Returns Acceptable
s = "README.1ST"; v.validate(s, pos); // Returns Acceptable
s = "read me.txt"; v.validate(s, pos); // Returns Invalid
s = "readm"; v.validate(s, pos); // Returns Intermediate
//! [6]

View File

@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtGui module of the Qt Toolkit.
@ -906,6 +907,159 @@ void QRegExpValidator::setRegExp(const QRegExp& rx)
#endif
#ifndef QT_NO_REGEXP
/*!
\class QRegularExpressionValidator
\brief The QRegularExpressionValidator class is used to check a string
against a regular expression.
\since 5.1
QRegularExpressionValidator uses a regular expression (regexp) to
determine whether an input string is \l Acceptable, \l
Intermediate, or \l Invalid. The regexp can either be supplied
when the QRegularExpressionValidator is constructed, or at a later time.
If the regexp partially matches against the string, the result is
considered \l Intermediate. For example, "" and "A" are \l Intermediate for
the regexp \b{[A-Z][0-9]} (whereas "_" would be \l Invalid).
QRegularExpressionValidator automatically wraps the regular expression in
the \c{\\A} and \c{\\z} anchors; in other words, it always attempts to do
an exact match.
Example of use:
\snippet code/src_gui_util_qvalidator.cpp 5
Below we present some examples of validators. In practice they would
normally be associated with a widget as in the example above.
\snippet code/src_gui_util_qvalidator.cpp 6
\sa QRegularExpression, QIntValidator, QDoubleValidator, QRegExpValidator
*/
class QRegularExpressionValidatorPrivate : public QValidatorPrivate
{
Q_DECLARE_PUBLIC(QRegularExpressionValidator)
public:
QRegularExpression origRe; // the one set by the user
QRegularExpression usedRe; // the one actually used
void setRegularExpression(const QRegularExpression &re);
};
/*!
Constructs a validator with a \a parent object that accepts
any string (including an empty one) as valid.
*/
QRegularExpressionValidator::QRegularExpressionValidator(QObject *parent)
: QValidator(*new QRegularExpressionValidatorPrivate, parent)
{
// origRe in the private will be an empty QRegularExpression,
// and therefore this validator will match any string.
}
/*!
Constructs a validator with a \a parent object that
accepts all strings that match the regular expression \a re.
*/
QRegularExpressionValidator::QRegularExpressionValidator(const QRegularExpression &re, QObject *parent)
: QValidator(*new QRegularExpressionValidatorPrivate, parent)
{
Q_D(QRegularExpressionValidator);
d->setRegularExpression(re);
}
/*!
Destroys the validator.
*/
QRegularExpressionValidator::~QRegularExpressionValidator()
{
}
/*!
Returns \l Acceptable if \a input is matched by the regular expression for
this validator, \l Intermediate if it has matched partially (i.e. could be
a valid match if additional valid characters are added), and \l Invalid if
\a input is not matched.
In case the \a input is not matched, the \a pos parameter is set to
the length of the \a input parameter; otherwise, it is not modified.
For example, if the regular expression is \b{\\w\\d\\d} (word-character,
digit, digit) then "A57" is \l Acceptable, "E5" is \l Intermediate, and
"+9" is \l Invalid.
\sa QRegularExpression::match()
*/
QValidator::State QRegularExpressionValidator::validate(QString &input, int &pos) const
{
Q_D(const QRegularExpressionValidator);
// We want a validator with an empty QRegularExpression to match anything;
// since we're going to do an exact match (by using d->usedRe), first check if the rx is empty
// (and, if so, accept the input).
if (d->origRe.pattern().isEmpty())
return Acceptable;
const QRegularExpressionMatch m = d->usedRe.match(input, 0, QRegularExpression::PartialPreferCompleteMatch);
if (m.hasMatch()) {
return Acceptable;
} else if (m.hasPartialMatch()) {
return Intermediate;
} else {
pos = input.size();
return Invalid;
}
}
/*!
\property QRegularExpressionValidator::regularExpression
\brief the regular expression used for validation
By default, this property contains a regular expression with an empty
pattern (which therefore matches any string).
*/
QRegularExpression QRegularExpressionValidator::regularExpression() const
{
Q_D(const QRegularExpressionValidator);
return d->origRe;
}
void QRegularExpressionValidator::setRegularExpression(const QRegularExpression &re)
{
Q_D(QRegularExpressionValidator);
d->setRegularExpression(re);
}
/*!
\internal
Sets \a re as the regular expression. It wraps the regexp that's actually used
between \\A and \\z, therefore forcing an exact match.
*/
void QRegularExpressionValidatorPrivate::setRegularExpression(const QRegularExpression &re)
{
Q_Q(QRegularExpressionValidator);
if (origRe != re) {
usedRe = origRe = re; // copies also the pattern options
usedRe.setPattern(QStringLiteral("\\A(?:") + re.pattern() + QStringLiteral(")\\z"));
emit q->regularExpressionChanged(re);
emit q->changed();
}
}
#endif // QT_NO_REGEXP
QT_END_NAMESPACE
#endif // QT_NO_VALIDATOR

View File

@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtGui module of the Qt Toolkit.
@ -45,6 +46,7 @@
#include <QtCore/qobject.h>
#include <QtCore/qstring.h>
#include <QtCore/qregexp.h>
#include <QtCore/qregularexpression.h>
#include <QtCore/qlocale.h>
QT_BEGIN_HEADER
@ -195,6 +197,37 @@ private:
#endif // QT_NO_REGEXP
#ifndef QT_NO_REGEXP
class QRegularExpressionValidatorPrivate;
class Q_GUI_EXPORT QRegularExpressionValidator : public QValidator
{
Q_OBJECT
Q_PROPERTY(QRegularExpression regularExpression READ regularExpression WRITE setRegularExpression NOTIFY regularExpressionChanged)
public:
explicit QRegularExpressionValidator(QObject *parent = 0);
explicit QRegularExpressionValidator(const QRegularExpression &re, QObject *parent = 0);
~QRegularExpressionValidator();
virtual QValidator::State validate(QString &input, int &pos) const Q_DECL_OVERRIDE;
QRegularExpression regularExpression() const;
public Q_SLOTS:
void setRegularExpression(const QRegularExpression &re);
Q_SIGNALS:
void regularExpressionChanged(const QRegularExpression &re);
private:
Q_DISABLE_COPY(QRegularExpressionValidator)
Q_DECLARE_PRIVATE(QRegularExpressionValidator)
};
#endif // QT_NO_REGEXP
#endif // QT_NO_VALIDATOR
QT_END_NAMESPACE

View File

@ -0,0 +1 @@
tst_qregularexpressionvalidator

View File

@ -0,0 +1,4 @@
CONFIG += testcase parallel_test
TARGET = tst_qregularexpressionvalidator
SOURCES += tst_qregularexpressionvalidator.cpp
QT += testlib

View File

@ -0,0 +1,120 @@
/****************************************************************************
**
** Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtGui/QRegularExpressionValidator>
#include <QtTest/QtTest>
class tst_QRegularExpressionValidator : public QObject
{
Q_OBJECT
private slots:
void validate_data();
void validate();
};
Q_DECLARE_METATYPE(QValidator::State)
void tst_QRegularExpressionValidator::validate_data()
{
QTest::addColumn<QRegularExpression>("re");
QTest::addColumn<QString>("value");
QTest::addColumn<QValidator::State>("state");
QTest::newRow("data0") << QRegularExpression("[1-9]\\d{0,3}") << QString("0") << QValidator::Invalid;
QTest::newRow("data1") << QRegularExpression("[1-9]\\d{0,3}") << QString("12345") << QValidator::Invalid;
QTest::newRow("data2") << QRegularExpression("[1-9]\\d{0,3}") << QString("1") << QValidator::Acceptable;
QTest::newRow("data3") << QRegularExpression("\\S+") << QString("myfile.txt") << QValidator::Acceptable;
QTest::newRow("data4") << QRegularExpression("\\S+") << QString("my file.txt") << QValidator::Invalid;
QTest::newRow("data5") << QRegularExpression("[A-C]\\d{5}[W-Z]") << QString("a12345Z") << QValidator::Invalid;
QTest::newRow("data6") << QRegularExpression("[A-C]\\d{5}[W-Z]") << QString("A12345Z") << QValidator::Acceptable;
QTest::newRow("data7") << QRegularExpression("[A-C]\\d{5}[W-Z]") << QString("B12") << QValidator::Intermediate;
QTest::newRow("data8") << QRegularExpression("read\\S?me(\\.(txt|asc|1st))?") << QString("readme") << QValidator::Acceptable;
QTest::newRow("data9") << QRegularExpression("read\\S?me(\\.(txt|asc|1st))?") << QString("read me.txt") << QValidator::Invalid;
QTest::newRow("data10") << QRegularExpression("read\\S?me(\\.(txt|asc|1st))?") << QString("readm") << QValidator::Intermediate;
QTest::newRow("data11") << QRegularExpression("read\\S?me(\\.(txt|asc|1st))?") << QString("read me.txt") << QValidator::Invalid;
QTest::newRow("data12") << QRegularExpression("read\\S?me(\\.(txt|asc|1st))?") << QString("readm") << QValidator::Intermediate;
QTest::newRow("data13") << QRegularExpression("\\w\\d\\d") << QString("A57") << QValidator::Acceptable;
QTest::newRow("data14") << QRegularExpression("\\w\\d\\d") << QString("E5") << QValidator::Intermediate;
QTest::newRow("data15") << QRegularExpression("\\w\\d\\d") << QString("+9") << QValidator::Invalid;
QTest::newRow("empty01") << QRegularExpression() << QString() << QValidator::Acceptable;
QTest::newRow("empty02") << QRegularExpression() << QString("test") << QValidator::Acceptable;
}
void tst_QRegularExpressionValidator::validate()
{
QFETCH(QRegularExpression, re);
QFETCH(QString, value);
QRegularExpressionValidator rv;
// setting the same regexp won't emit signals
const int signalCount = (rv.regularExpression() == re) ? 0 : 1;
QSignalSpy spy(&rv, SIGNAL(regularExpressionChanged(QRegularExpression)));
QSignalSpy changedSpy(&rv, SIGNAL(changed()));
rv.setRegularExpression(re);
QCOMPARE(rv.regularExpression(), re);
int pos = -1;
QValidator::State result = rv.validate(value, pos);
QTEST(result, "state");
if (result == QValidator::Invalid)
QCOMPARE(pos, value.length());
else
QCOMPARE(pos, -1); // ensure pos is not modified if validate returned Acceptable or Intermediate
QCOMPARE(spy.count(), signalCount);
QCOMPARE(changedSpy.count(), signalCount);
}
QTEST_GUILESS_MAIN(tst_QRegularExpressionValidator)
#include "tst_qregularexpressionvalidator.moc"

View File

@ -4,4 +4,5 @@ SUBDIRS= \
qdoublevalidator \
qintvalidator \
qregexpvalidator \
qregularexpressionvalidator \