Refactor wildcard support in QRegularExpression
The API originally proposed was flawed in the sense that the setter function would use a modified version of the parameter given which would have make it a black box for the user. This patch fixes that by removing that setter and providing a static method that will return the pattern suitably modified to be used by QRegularExpression the same way the escape method does. [ChangeLog][Core][QRegularExpression] Implemented support for wildcard patterns through a static method. Change-Id: I0054bcaffd7525dac569f54fa81f73b7e4544b2e Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>bb10
parent
0f6b941ca5
commit
30b0701c9b
|
|
@ -350,4 +350,11 @@ while (i.hasNext()) {
|
|||
//! [30]
|
||||
}
|
||||
|
||||
{
|
||||
//! [31]
|
||||
QString wildcard = QRegularExpression::wildcardToRegularExpression("*.jpeg");
|
||||
// wilcard == ".*\.jpeg"
|
||||
//! [31]
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -516,10 +516,10 @@ QT_BEGIN_NAMESPACE
|
|||
|
||||
\section2 Wildcard matching
|
||||
|
||||
There is no equivalent of wildcard matching in QRegularExpression.
|
||||
Nevertheless, rewriting a regular expression in wildcard syntax to a
|
||||
Perl-compatible regular expression is a very easy task, given the fact
|
||||
that wildcard syntax supported by QRegExp is very simple.
|
||||
There is no direct way to do wildcard matching in QRegularExpression.
|
||||
However, the wildcardToRegularExpression method is provided to translate
|
||||
glob patterns into a Perl-compatible regular expression that can be used
|
||||
for that purpose.
|
||||
|
||||
\section2 Other pattern syntaxes
|
||||
|
||||
|
|
@ -784,82 +784,6 @@ QT_BEGIN_NAMESPACE
|
|||
Qt 5.4.
|
||||
*/
|
||||
|
||||
namespace QtPrivate {
|
||||
/*!
|
||||
internal
|
||||
*/
|
||||
QString wildcardToRegularExpression(const QString &wildcardString)
|
||||
{
|
||||
const int wclen = wildcardString.length();
|
||||
QString rx;
|
||||
int i = 0;
|
||||
bool hasNegativeBracket = false;
|
||||
const QChar *wc = wildcardString.unicode();
|
||||
|
||||
while (i < wclen) {
|
||||
const QChar c = wc[i++];
|
||||
switch (c.unicode()) {
|
||||
case '*':
|
||||
rx += QLatin1String(".*");
|
||||
break;
|
||||
case '?':
|
||||
rx += QLatin1Char('.');
|
||||
break;
|
||||
case '$':
|
||||
case '(':
|
||||
case ')':
|
||||
case '+':
|
||||
case '.':
|
||||
case '^':
|
||||
case '{':
|
||||
case '|':
|
||||
case '}':
|
||||
rx += QLatin1Char('\\');
|
||||
rx += c;
|
||||
break;
|
||||
case '[':
|
||||
// Support for the [!abc] or [!a-c] syntax
|
||||
// Implements a negative look-behind for one char.
|
||||
if (wc[i] == QLatin1Char(']')) {
|
||||
rx += c;
|
||||
rx += wc[i++];
|
||||
} else if (wc[i] == QLatin1Char('!')) {
|
||||
rx += QLatin1String(".(?<");
|
||||
rx += wc[i++];
|
||||
rx += c;
|
||||
hasNegativeBracket = true;
|
||||
} else {
|
||||
rx += c;
|
||||
}
|
||||
|
||||
if (i < wclen) {
|
||||
if (rx[i] == QLatin1Char(']'))
|
||||
rx += wc[i++];
|
||||
while (i < wclen && wc[i] != QLatin1Char(']')) {
|
||||
if (wc[i] == QLatin1Char('\\'))
|
||||
rx += QLatin1Char('\\');
|
||||
rx += wc[i++];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ']':
|
||||
rx += c;
|
||||
// Closes the negative look-behind expression.
|
||||
if (hasNegativeBracket) {
|
||||
rx += QLatin1Char(')');
|
||||
hasNegativeBracket = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rx += c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rx;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
|
|
@ -1582,47 +1506,6 @@ void QRegularExpression::setPattern(const QString &pattern)
|
|||
d->pattern = pattern;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 5.12
|
||||
|
||||
Sets the pattern string of the regular expression to \a wildcard pattern.
|
||||
The pattern options are left unchanged.
|
||||
|
||||
\warning Unlike QRegExp, this implementation follows closely the definition
|
||||
of wildcard for glob patterns:
|
||||
\table
|
||||
\row \li \b{c}
|
||||
\li Any character represents itself apart from those mentioned
|
||||
below. Thus \b{c} matches the character \e c.
|
||||
\row \li \b{?}
|
||||
\li Matches any single character. It is the same as
|
||||
\b{.} in full regexps.
|
||||
\row \li \b{*}
|
||||
\li Matches zero or more of any characters. It is the
|
||||
same as \b{.*} in full regexps.
|
||||
\row \li \b{[abc]}
|
||||
\li Matches one character given in the bracket.
|
||||
\row \li \b{[a-c]}
|
||||
\li Matches one character from the range given in the bracket.
|
||||
\row \li \b{[!abc]}
|
||||
\li Matches one character that is not given in the bracket.
|
||||
\row \li \b{[!a-c]}
|
||||
\li matches one character that is not from the range given in the
|
||||
bracket.
|
||||
\endtable
|
||||
|
||||
\note This function generates a regular expression that will act following
|
||||
the wildcard pattern given. However the content of the regular expression
|
||||
will not be the same as the one set.
|
||||
|
||||
\sa pattern(), setPattern()
|
||||
*/
|
||||
void QRegularExpression::setWildcardPattern(const QString &pattern)
|
||||
{
|
||||
setPattern(QtPrivate::wildcardToRegularExpression(pattern));
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Returns the pattern options for the regular expression.
|
||||
|
||||
|
|
@ -1987,6 +1870,119 @@ QString QRegularExpression::escape(const QString &str)
|
|||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 5.12
|
||||
|
||||
Returns a regular expression representation of the given glob \a pattern.
|
||||
|
||||
\snippet code/src_corelib_tools_qregularexpression.cpp 31
|
||||
|
||||
\warning Unlike QRegExp, this implementation follows closely the definition
|
||||
of wildcard for glob patterns:
|
||||
\table
|
||||
\row \li \b{c}
|
||||
\li Any character represents itself apart from those mentioned
|
||||
below. Thus \b{c} matches the character \e c.
|
||||
\row \li \b{?}
|
||||
\li Matches any single character. It is the same as
|
||||
\b{.} in full regexps.
|
||||
\row \li \b{*}
|
||||
\li Matches zero or more of any characters. It is the
|
||||
same as \b{.*} in full regexps.
|
||||
\row \li \b{[abc]}
|
||||
\li Matches one character given in the bracket.
|
||||
\row \li \b{[a-c]}
|
||||
\li Matches one character from the range given in the bracket.
|
||||
\row \li \b{[!abc]}
|
||||
\li Matches one character that is not given in the bracket. It is the
|
||||
same as \b{[^abc]} in full regexp.
|
||||
\row \li \b{[!a-c]}
|
||||
\li Matches one character that is not from the range given in the
|
||||
bracket. It is the same as \b{[^a-c]} in full regexp.
|
||||
\endtable
|
||||
|
||||
\note The backslash (\\) character is \e not an escape char in this context.
|
||||
In order to match one of the special characters, place it in square brackets
|
||||
(for example, "[?]").
|
||||
|
||||
More information about the implementation can be found in:
|
||||
\list
|
||||
\li \l {https://en.wikipedia.org/wiki/Glob_(programming)} {The Wikipedia Glob article}
|
||||
\li \c man 7 glob
|
||||
\endlist
|
||||
|
||||
\sa escape()
|
||||
*/
|
||||
QString QRegularExpression::wildcardToRegularExpression(const QString &pattern)
|
||||
{
|
||||
const int wclen = pattern.length();
|
||||
QString rx;
|
||||
int i = 0;
|
||||
bool hasNegativeBracket = false;
|
||||
const QChar *wc = pattern.unicode();
|
||||
|
||||
while (i < wclen) {
|
||||
const QChar c = wc[i++];
|
||||
switch (c.unicode()) {
|
||||
case '*':
|
||||
rx += QLatin1String(".*");
|
||||
break;
|
||||
case '?':
|
||||
rx += QLatin1Char('.');
|
||||
break;
|
||||
case '$':
|
||||
case '(':
|
||||
case ')':
|
||||
case '+':
|
||||
case '.':
|
||||
case '^':
|
||||
case '{':
|
||||
case '|':
|
||||
case '}':
|
||||
rx += QLatin1Char('\\');
|
||||
rx += c;
|
||||
break;
|
||||
case '[':
|
||||
// Support for the [!abc] or [!a-c] syntax
|
||||
// Implements a negative look-behind for one char.
|
||||
if (i < wclen) {
|
||||
if (wc[i] == QLatin1Char(']')) {
|
||||
rx += c;
|
||||
rx += wc[i++];
|
||||
} else if (wc[i] == QLatin1Char('!')) {
|
||||
rx += QLatin1String(".(?<");
|
||||
rx += wc[i++];
|
||||
rx += c;
|
||||
hasNegativeBracket = true;
|
||||
} else {
|
||||
rx += c;
|
||||
}
|
||||
while (i < wclen && wc[i] != QLatin1Char(']')) {
|
||||
if (wc[i] == QLatin1Char('\\'))
|
||||
rx += QLatin1Char('\\');
|
||||
rx += wc[i++];
|
||||
}
|
||||
} else {
|
||||
rx += c;
|
||||
}
|
||||
break;
|
||||
case ']':
|
||||
rx += c;
|
||||
// Closes the negative look-behind expression.
|
||||
if (hasNegativeBracket) {
|
||||
rx += QLatin1Char(')');
|
||||
hasNegativeBracket = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rx += c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rx;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 5.1
|
||||
|
||||
|
|
|
|||
|
|
@ -96,7 +96,6 @@ public:
|
|||
|
||||
QString pattern() const;
|
||||
void setPattern(const QString &pattern);
|
||||
void setWildcardPattern(const QString &pattern);
|
||||
|
||||
bool isValid() const;
|
||||
int patternErrorOffset() const;
|
||||
|
|
@ -142,6 +141,7 @@ public:
|
|||
void optimize() const;
|
||||
|
||||
static QString escape(const QString &str);
|
||||
static QString wildcardToRegularExpression(const QString &str);
|
||||
|
||||
bool operator==(const QRegularExpression &re) const;
|
||||
inline bool operator!=(const QRegularExpression &re) const { return !operator==(re); }
|
||||
|
|
|
|||
|
|
@ -1,70 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 Samuel Gaist <samuel.gaist@edeltech.ch>
|
||||
** Copyright (C) 2018 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtCore module 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 The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QREGULAREXPRESSION_P_H
|
||||
#define QREGULAREXPRESSION_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include <private/qglobal_p.h>
|
||||
|
||||
#include <qregularexpression.h>
|
||||
#include <qstring.h>
|
||||
|
||||
QT_REQUIRE_CONFIG(regularexpression);
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QtPrivate {
|
||||
QString wildcardToRegularExpression(const QString &expression);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif
|
||||
|
|
@ -183,8 +183,7 @@ qtConfig(regularexpression) {
|
|||
QMAKE_USE_PRIVATE += pcre2
|
||||
|
||||
HEADERS += \
|
||||
tools/qregularexpression.h \
|
||||
tools/qregularexpression_p.h
|
||||
tools/qregularexpression.h
|
||||
SOURCES += tools/qregularexpression.cpp
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2171,6 +2171,10 @@ void tst_QRegularExpression::wildcard_data()
|
|||
addRow(".???l", "test.html", 4);
|
||||
addRow("?", "test.html", 0);
|
||||
addRow("?m", "test.html", 6);
|
||||
addRow("[*]", "test.html", -1);
|
||||
addRow("[?]","test.html", -1);
|
||||
addRow("[[]","test.h[ml", 6);
|
||||
addRow("[]]","test.h]ml", 6);
|
||||
addRow(".h[a-z]ml", "test.html", 4);
|
||||
addRow(".h[A-Z]ml", "test.html", -1);
|
||||
addRow(".h[A-Z]ml", "test.hTml", 4);
|
||||
|
|
@ -2191,9 +2195,7 @@ void tst_QRegularExpression::wildcard()
|
|||
QFETCH(QString, string);
|
||||
QFETCH(int, foundIndex);
|
||||
|
||||
QRegularExpression re;
|
||||
re.setWildcardPattern(pattern);
|
||||
|
||||
QRegularExpression re(QRegularExpression::wildcardToRegularExpression(pattern));
|
||||
QRegularExpressionMatch match = re.match(string);
|
||||
|
||||
QCOMPARE(match.capturedStart(), foundIndex);
|
||||
|
|
@ -2217,11 +2219,9 @@ void tst_QRegularExpression::testInvalidWildcard_data()
|
|||
void tst_QRegularExpression::testInvalidWildcard()
|
||||
{
|
||||
QFETCH(QString, pattern);
|
||||
|
||||
QRegularExpression re;
|
||||
re.setWildcardPattern(pattern);
|
||||
|
||||
QFETCH(bool, isValid);
|
||||
|
||||
QRegularExpression re(QRegularExpression::wildcardToRegularExpression(pattern));
|
||||
QCOMPARE(re.isValid(), isValid);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue