diff options
author | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2020-12-02 12:31:41 +0100 |
---|---|---|
committer | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2020-12-10 02:15:18 +0100 |
commit | ce0b76731042412a0fa5a5f633fc48a52f79ef81 (patch) | |
tree | b0e697beba8c24158a6312341417b82b6a561d2c | |
parent | be83ff65c424cff1036e7da19d6175826d9f7ed9 (diff) |
QStringView: add some QRegularExpression-related overloads
[ChangeLog][QtCore][QStringView] Added the indexOf(), contains(),
lastIndexOf() and count() methods taking a QRegularExpression.
Fixes: QTBUG-89050
Change-Id: Ic726754f67e06b3764302d2fad252e0378a77afc
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
-rw-r--r-- | src/corelib/text/qstring.cpp | 78 | ||||
-rw-r--r-- | src/corelib/text/qstringalgorithms.h | 17 | ||||
-rw-r--r-- | src/corelib/text/qstringview.cpp | 61 | ||||
-rw-r--r-- | src/corelib/text/qstringview.h | 20 | ||||
-rw-r--r-- | tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp | 207 |
5 files changed, 383 insertions, 0 deletions
diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index 92eed93251..07b8c8512b 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -10259,6 +10259,84 @@ qsizetype QtPrivate::lastIndexOf(QLatin1String haystack, qsizetype from, QLatin1 return qLastIndexOf(haystack, from, needle, cs); } +#if QT_CONFIG(regularexpression) +qsizetype QtPrivate::indexOf(QStringView haystack, const QRegularExpression &re, qsizetype from, QRegularExpressionMatch *rmatch) +{ + if (!re.isValid()) { + qWarning("QStringView::indexOf: invalid QRegularExpression object"); + return -1; + } + + QRegularExpressionMatch match = re.match(haystack, from); + if (match.hasMatch()) { + const qsizetype ret = match.capturedStart(); + if (rmatch) + *rmatch = std::move(match); + return ret; + } + + return -1; +} + +qsizetype QtPrivate::lastIndexOf(QStringView haystack, const QRegularExpression &re, qsizetype from, QRegularExpressionMatch *rmatch) +{ + if (!re.isValid()) { + qWarning("QStringView::lastIndexOf: invalid QRegularExpression object"); + return -1; + } + + qsizetype endpos = (from < 0) ? (haystack.size() + from + 1) : (from); + QRegularExpressionMatchIterator iterator = re.globalMatch(haystack); + qsizetype lastIndex = -1; + while (iterator.hasNext()) { + QRegularExpressionMatch match = iterator.next(); + qsizetype start = match.capturedStart(); + if (start <= endpos) { + lastIndex = start; + if (rmatch) + *rmatch = std::move(match); + } else { + break; + } + } + + return lastIndex; +} + +bool QtPrivate::contains(QStringView haystack, const QRegularExpression &re, QRegularExpressionMatch *rmatch) +{ + if (!re.isValid()) { + qWarning("QStringView::contains: invalid QRegularExpression object"); + return false; + } + QRegularExpressionMatch m = re.match(haystack); + bool hasMatch = m.hasMatch(); + if (hasMatch && rmatch) + *rmatch = std::move(m); + return hasMatch; +} + +qsizetype QtPrivate::count(QStringView haystack, const QRegularExpression &re) +{ + if (!re.isValid()) { + qWarning("QStringView::count: invalid QRegularExpression object"); + return 0; + } + qsizetype count = 0; + qsizetype index = -1; + qsizetype len = haystack.length(); + while (index <= len - 1) { + QRegularExpressionMatch match = re.match(haystack, index + 1); + if (!match.hasMatch()) + break; + index = match.capturedStart(); + count++; + } + return count; +} + +#endif // QT_CONFIG(regularexpression) + /*! \since 5.0 diff --git a/src/corelib/text/qstringalgorithms.h b/src/corelib/text/qstringalgorithms.h index 6d8fe114f1..870ae42af8 100644 --- a/src/corelib/text/qstringalgorithms.h +++ b/src/corelib/text/qstringalgorithms.h @@ -70,6 +70,8 @@ class QStringView; template <bool> class QBasicUtf8StringView; class QAnyStringView; class QChar; +class QRegularExpression; +class QRegularExpressionMatch; namespace QtPrivate { @@ -122,6 +124,21 @@ namespace QtPrivate { [[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype count(QStringView haystack, QChar needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept; [[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype count(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept; +#if QT_CONFIG(regularexpression) +[[nodiscard]] Q_CORE_EXPORT qsizetype indexOf(QStringView haystack, + const QRegularExpression &re, + qsizetype from = 0, + QRegularExpressionMatch *rmatch = nullptr); +[[nodiscard]] Q_CORE_EXPORT qsizetype lastIndexOf(QStringView haystack, + const QRegularExpression &re, + qsizetype from = -1, + QRegularExpressionMatch *rmatch = nullptr); +[[nodiscard]] Q_CORE_EXPORT bool contains(QStringView haystack, + const QRegularExpression &re, + QRegularExpressionMatch *rmatch = nullptr); +[[nodiscard]] Q_CORE_EXPORT qsizetype count(QStringView haystack, const QRegularExpression &re); +#endif + [[nodiscard]] Q_CORE_EXPORT QString convertToQString(QAnyStringView s); [[nodiscard]] Q_CORE_EXPORT QByteArray convertToLatin1(QStringView str); diff --git a/src/corelib/text/qstringview.cpp b/src/corelib/text/qstringview.cpp index 1b8db705b4..b64d128a65 100644 --- a/src/corelib/text/qstringview.cpp +++ b/src/corelib/text/qstringview.cpp @@ -881,6 +881,67 @@ QT_BEGIN_NAMESPACE \sa QString::lastIndexOf() */ +#if QT_CONFIG(regularexpression) +/*! + \fn qsizetype QStringView::indexOf(const QRegularExpression &re, qsizetype from, QRegularExpressionMatch *rmatch) const + \since 6.1 + + Returns the index position of the first match of the regular + expression \a re in the string view, searching forward from index + position \a from. Returns -1 if \a re didn't match anywhere. + + If the match is successful and \a rmatch is not \nullptr, it also + writes the results of the match into the QRegularExpressionMatch object + pointed to by \a rmatch. + + \note Due to how the regular expression matching algorithm works, + this function will actually match repeatedly from the beginning of + the string view until the position \a from is reached. +*/ + +/*! + \fn qsizetype QStringView::lastIndexOf(const QRegularExpression &re, qsizetype from, QRegularExpressionMatch *rmatch) const + \since 6.1 + + Returns the index position of the last match of the regular + expression \a re in the string view, which starts before the index + position \a from. Returns -1 if \a re didn't match anywhere. + + If the match is successful and \a rmatch is not \nullptr, it also + writes the results of the match into the QRegularExpressionMatch object + pointed to by \a rmatch. +*/ + +/*! + \fn bool QStringView::contains(const QRegularExpression &re, QRegularExpressionMatch *rmatch) const + \since 6.1 + + Returns \c true if the regular expression \a re matches somewhere in this + string view; otherwise returns \c false. + + If the match is successful and \a rmatch is not \nullptr, it also + writes the results of the match into the QRegularExpressionMatch object + pointed to by \a rmatch. + + \sa QRegularExpression::match() +*/ + +/*! + \fn qsizetype QStringView::count(const QRegularExpression &re) const + \since 6.1 + + Returns the number of times the regular expression \a re matches + in the string view. + + For historical reasons, this function counts overlapping matches. + This behavior is different from simply iterating over the matches + in the string using QRegularExpressionMatchIterator. + + \sa QRegularExpression::globalMatch() + +*/ +#endif // QT_CONFIG(regularexpression) + /*! \fn QByteArray QStringView::toLatin1() const diff --git a/src/corelib/text/qstringview.h b/src/corelib/text/qstringview.h index df05fce252..42935440f3 100644 --- a/src/corelib/text/qstringview.h +++ b/src/corelib/text/qstringview.h @@ -71,6 +71,7 @@ QT_BEGIN_NAMESPACE class QString; class QStringView; class QRegularExpression; +class QRegularExpressionMatch; namespace QtPrivate { template <typename Char> @@ -347,6 +348,25 @@ public: { return QtPrivate::lastIndexOf(*this, from, s, cs); } [[nodiscard]] inline qsizetype lastIndexOf(QLatin1String s, qsizetype from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept; +#if QT_CONFIG(regularexpression) + [[nodiscard]] qsizetype indexOf(const QRegularExpression &re, qsizetype from = 0, QRegularExpressionMatch *rmatch = nullptr) const + { + return QtPrivate::indexOf(*this, re, from, rmatch); + } + [[nodiscard]] qsizetype lastIndexOf(const QRegularExpression &re, qsizetype from = -1, QRegularExpressionMatch *rmatch = nullptr) const + { + return QtPrivate::lastIndexOf(*this, re, from, rmatch); + } + [[nodiscard]] bool contains(const QRegularExpression &re, QRegularExpressionMatch *rmatch = nullptr) const + { + return QtPrivate::contains(*this, re, rmatch); + } + [[nodiscard]] qsizetype count(const QRegularExpression &re) const + { + return QtPrivate::count(*this, re); + } +#endif + [[nodiscard]] bool isRightToLeft() const noexcept { return QtPrivate::isRightToLeft(*this); } [[nodiscard]] bool isValidUtf16() const noexcept diff --git a/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp b/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp index 7a3448fdd6..58a3b56b68 100644 --- a/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp +++ b/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp @@ -830,6 +830,16 @@ private Q_SLOTS: void lastIndexOf_QStringView_QChar() { lastIndexOf_impl<QStringView, QChar>(); } void lastIndexOf_QStringView_char16_t_data() { lastIndexOf_data(false); } void lastIndexOf_QStringView_char16_t() { lastIndexOf_impl<QStringView, char16_t>(); } + +private: + void indexOf_contains_lastIndexOf_count_regexp_data(); + template <typename String> void indexOf_contains_lastIndexOf_count_regexp_impl() const; + +private Q_SLOTS: + void indexOf_regexp_QString_data() { indexOf_contains_lastIndexOf_count_regexp_data(); } + void indexOf_regexp_QString() { indexOf_contains_lastIndexOf_count_regexp_impl<QString>(); } + void indexOf_regexp_QStringView_data() { indexOf_contains_lastIndexOf_count_regexp_data(); } + void indexOf_regexp_QStringView() { indexOf_contains_lastIndexOf_count_regexp_impl<QStringView>(); } }; void tst_QStringApiSymmetry::compare_data(bool hasConceptOfNullAndEmpty) @@ -2496,6 +2506,203 @@ void tst_QStringApiSymmetry::lastIndexOf_impl() const } +void tst_QStringApiSymmetry::indexOf_contains_lastIndexOf_count_regexp_data() +{ + QTest::addColumn<QString>("subject"); + QTest::addColumn<QRegularExpression>("regexp"); + QTest::addColumn<qsizetype>("leftFrom"); + QTest::addColumn<qsizetype>("indexOf"); + QTest::addColumn<qsizetype>("count"); + QTest::addColumn<qsizetype>("rightFrom"); + QTest::addColumn<qsizetype>("lastIndexOf"); + + const auto ROW = [](const char *subject, + const char *pattern, + QRegularExpression::PatternOptions options, + qsizetype leftFrom, qsizetype indexOf, qsizetype count, + qsizetype rightFrom, qsizetype lastIndexOf) + { + QTest::addRow("subject \"%s\" pattern \"%s\" options %d leftFrom %d rightFrom %d", + subject, pattern, (int)options, (int)leftFrom, (int)rightFrom) + << subject + << QRegularExpression(pattern, options) + << leftFrom + << indexOf + << count + << rightFrom + << lastIndexOf; + }; + + ROW("", "", QRegularExpression::NoPatternOption, 0, 0, 1, -1, 0); + ROW("test", "", QRegularExpression::NoPatternOption, 0, 0, 5, -1, 4); + ROW("", "^", QRegularExpression::NoPatternOption, 0, 0, 1, -1, 0); + ROW("", "$", QRegularExpression::NoPatternOption, 0, 0, 1, -1, 0); + ROW("", "^$", QRegularExpression::NoPatternOption, 0, 0, 1, -1, 0); + ROW("", "x", QRegularExpression::NoPatternOption, 0, -1, 0, -1, -1); + ROW("", "^x", QRegularExpression::NoPatternOption, 0, -1, 0, -1, -1); + ROW("", "x$", QRegularExpression::NoPatternOption, 0, -1, 0, -1, -1); + ROW("", "^x$", QRegularExpression::NoPatternOption, 0, -1, 0, -1, -1); + + ROW("test", "e", QRegularExpression::NoPatternOption, 0, 1, 1, -1, 1); + ROW("test", "e", QRegularExpression::NoPatternOption, 0, 1, 1, -2, 1); + ROW("test", "es", QRegularExpression::NoPatternOption, 0, 1, 1, -1, 1); + ROW("test", "es", QRegularExpression::NoPatternOption, 0, 1, 1, -2, 1); + ROW("test", "es?", QRegularExpression::NoPatternOption, 0, 1, 1, -1, 1); + ROW("test", "es?", QRegularExpression::NoPatternOption, 0, 1, 1, -2, 1); + ROW("test", "es+", QRegularExpression::NoPatternOption, 0, 1, 1, -1, 1); + ROW("test", "es+", QRegularExpression::NoPatternOption, 0, 1, 1, -2, 1); + ROW("test", "e.", QRegularExpression::NoPatternOption, 0, 1, 1, -1, 1); + ROW("test", "e.", QRegularExpression::NoPatternOption, 0, 1, 1, -2, 1); + ROW("test", "e.*", QRegularExpression::NoPatternOption, 0, 1, 1, -1, 1); + ROW("test", "e.*", QRegularExpression::NoPatternOption, 0, 1, 1, -2, 1); + ROW("test", "e(?=s)", QRegularExpression::NoPatternOption, 0, 1, 1, -1, 1); + ROW("test", "e(?!x)", QRegularExpression::NoPatternOption, 0, 1, 1, -1, 1); + ROW("test", "ex?s", QRegularExpression::NoPatternOption, 0, 1, 1, -1, 1); + ROW("test", "(?<=t)e", QRegularExpression::NoPatternOption, 0, 1, 1, -1, 1); + ROW("test", "(?<!x)e", QRegularExpression::NoPatternOption, 0, 1, 1, -1, 1); + ROW("test", "t", QRegularExpression::NoPatternOption, 0, 0, 2, 0, 0); + ROW("test", "t", QRegularExpression::NoPatternOption, 0, 0, 2, 1, 0); + ROW("test", "t", QRegularExpression::NoPatternOption, 0, 0, 2, -1, 3); + ROW("test", "t", QRegularExpression::NoPatternOption, 0, 0, 2, -2, 3); + ROW("test", "t", QRegularExpression::NoPatternOption, 0, 0, 2, -3, 0); + + ROW("test", "^es", QRegularExpression::NoPatternOption, 0, -1, 0, -1, -1); + ROW("test", "^es", QRegularExpression::NoPatternOption, 0, -1, 0, -2, -1); + ROW("test", "es$", QRegularExpression::NoPatternOption, 0, -1, 0, -1, -1); + ROW("test", "ex", QRegularExpression::NoPatternOption, 0, -1, 0, -1, -1); + ROW("test", "ex?", QRegularExpression::NoPatternOption, 0, 1, 1, -1, 1); + ROW("test", "ex+", QRegularExpression::NoPatternOption, 0, -1, 0, -1, -1); + ROW("test", "e(?=x)", QRegularExpression::NoPatternOption, 0, -1, 0, -1, -1); + ROW("test", "e(?!s)", QRegularExpression::NoPatternOption, 0, -1, 0, -1, -1); + + + ROW("test", "e.*t", QRegularExpression::NoPatternOption, 0, 1, 1, -1, 1); + ROW("test", "e.*t", QRegularExpression::NoPatternOption, 0, 1, 1, -2, 1); + ROW("test", "e.*t", QRegularExpression::NoPatternOption, 0, 1, 1, -3, 1); + ROW("test", "e.*t", QRegularExpression::NoPatternOption, 0, 1, 1, -4, 1); + ROW("test", "e.*t", QRegularExpression::NoPatternOption, 0, 1, 1, -5, -1); + ROW("test", "e.*t$", QRegularExpression::NoPatternOption, 0, 1, 1, -1, 1); + ROW("test", "e.*t$", QRegularExpression::NoPatternOption, 0, 1, 1, -2, 1); + ROW("test", "e.*st", QRegularExpression::NoPatternOption, 0, 1, 1, -1, 1); + ROW("test", "e.*st$", QRegularExpression::NoPatternOption, 0, 1, 1, -1, 1); + ROW("test", "t.*t", QRegularExpression::NoPatternOption, 0, 0, 1, -1, 0); + ROW("test", "t.*t", QRegularExpression::NoPatternOption, 0, 0, 1, -2, 0); + ROW("test", "st", QRegularExpression::NoPatternOption, 0, 2, 1, -1, 2); + ROW("test", "st", QRegularExpression::NoPatternOption, 0, 2, 1, -2, 2); + ROW("test", "st", QRegularExpression::NoPatternOption, 0, 2, 1, -3, 2); + ROW("test", "st", QRegularExpression::NoPatternOption, 0, 2, 1, -4, -1); + + ROW("", "", QRegularExpression::CaseInsensitiveOption, 0, 0, 1, -1, 0); + ROW("test", "", QRegularExpression::CaseInsensitiveOption, 0, 0, 5, -1, 4); + ROW("test", "^", QRegularExpression::CaseInsensitiveOption, 0, 0, 1, -1, 0); + ROW("test", "^t", QRegularExpression::CaseInsensitiveOption, 0, 0, 1, -1, 0); + ROW("TEST", "^t", QRegularExpression::CaseInsensitiveOption, 0, 0, 1, -1, 0); + ROW("test", "e", QRegularExpression::CaseInsensitiveOption, 0, 1, 1, -1, 1); + ROW("TEST", "e", QRegularExpression::CaseInsensitiveOption, 0, 1, 1, -1, 1); + ROW("TEST", "es", QRegularExpression::CaseInsensitiveOption, 0, 1, 1, -1, 1); + ROW("test", "ES", QRegularExpression::CaseInsensitiveOption, 0, 1, 1, -1, 1); + ROW("TEST", "ex?s", QRegularExpression::CaseInsensitiveOption, 0, 1, 1, -1, 1); + + ROW("testtest", "e", QRegularExpression::NoPatternOption, 0, 1, 2, -1, 5); + ROW("testtest", "e", QRegularExpression::NoPatternOption, 0, 1, 2, -2, 5); + ROW("testtest", "e", QRegularExpression::NoPatternOption, 0, 1, 2, -3, 5); + ROW("testtest", "e", QRegularExpression::NoPatternOption, 0, 1, 2, -4, 5); + ROW("testtest", "e", QRegularExpression::NoPatternOption, 0, 1, 2, -5, 1); + ROW("testtest", "e", QRegularExpression::NoPatternOption, 0, 1, 2, -6, 1); + ROW("testtest", "e", QRegularExpression::NoPatternOption, 0, 1, 2, -7, 1); + ROW("testtest", "e", QRegularExpression::NoPatternOption, 0, 1, 2, -8, 1); + ROW("testtest", "es", QRegularExpression::NoPatternOption, 0, 1, 2, -1, 5); + ROW("testtest", "e.*s", QRegularExpression::NoPatternOption, 0, 1, 2, -1, 1); + + ROW("testtest", "e", QRegularExpression::NoPatternOption, 1, 1, 2, -1, 5); + ROW("testtest", "es", QRegularExpression::NoPatternOption, 1, 1, 2, -1, 5); + ROW("testtest", "e.*s", QRegularExpression::NoPatternOption, 1, 1, 2, -1, 1); + ROW("testtest", "e", QRegularExpression::NoPatternOption, 2, 5, 1, -1, 5); + ROW("testtest", "es", QRegularExpression::NoPatternOption, 2, 5, 1, -1, 5); + ROW("testtest", "es", QRegularExpression::NoPatternOption, 2, 5, 1, -2, 5); + ROW("testtest", "es", QRegularExpression::NoPatternOption, 2, 5, 1, -3, 5); + ROW("testtest", "es", QRegularExpression::NoPatternOption, 2, 5, 1, -4, 5); + ROW("testtest", "es", QRegularExpression::NoPatternOption, 2, 5, 1, -5, 1); + ROW("testtest", "e.*s", QRegularExpression::NoPatternOption, 2, 5, 1, -1, 1); + + ROW("testtest", "e", QRegularExpression::NoPatternOption, -1, -1, 0, 0, -1); + ROW("testtest", "e", QRegularExpression::NoPatternOption, -1, -1, 0, 1, 1); + ROW("testtest", "e", QRegularExpression::NoPatternOption, -1, -1, 0, 2, 1); + ROW("testtest", "e", QRegularExpression::NoPatternOption, -1, -1, 0, 3, 1); + ROW("testtest", "e", QRegularExpression::NoPatternOption, -1, -1, 0, 4, 1); + ROW("testtest", "e", QRegularExpression::NoPatternOption, -1, -1, 0, 5, 5); + ROW("testtest", "e", QRegularExpression::NoPatternOption, -1, -1, 0, 6, 5); + ROW("testtest", "e", QRegularExpression::NoPatternOption, -1, -1, 0, 7, 5); + ROW("testtest", "e", QRegularExpression::NoPatternOption, -2, -1, 0, -1, 5); + ROW("testtest", "e", QRegularExpression::NoPatternOption, -3, 5, 1, -1, 5); + ROW("testtest", "e", QRegularExpression::NoPatternOption, -4, 5, 1, -1, 5); + ROW("testtest", "t", QRegularExpression::NoPatternOption, 0, 0, 4, 0, 0); + ROW("testtest", "t", QRegularExpression::NoPatternOption, 0, 0, 4, 1, 0); + ROW("testtest", "t", QRegularExpression::NoPatternOption, 0, 0, 4, 2, 0); + ROW("testtest", "t", QRegularExpression::NoPatternOption, 0, 0, 4, 3, 3); + ROW("testtest", "t", QRegularExpression::NoPatternOption, 0, 0, 4, 4, 4); + ROW("testtest", "t", QRegularExpression::NoPatternOption, 0, 0, 4, 5, 4); + ROW("testtest", "t", QRegularExpression::NoPatternOption, 0, 0, 4, 6, 4); + ROW("testtest", "t", QRegularExpression::NoPatternOption, 0, 0, 4, 7, 7); + ROW("testtest", "t(?!e)", QRegularExpression::NoPatternOption, 0, 3, 2, 0, -1); + ROW("testtest", "t(?!e)", QRegularExpression::NoPatternOption, 0, 3, 2, 1, -1); + ROW("testtest", "t(?!e)", QRegularExpression::NoPatternOption, 0, 3, 2, 2, -1); + ROW("testtest", "t(?!e)", QRegularExpression::NoPatternOption, 0, 3, 2, 3, 3); + ROW("testtest", "t(?!e)", QRegularExpression::NoPatternOption, 0, 3, 2, 4, 3); + ROW("testtest", "t(?!e)", QRegularExpression::NoPatternOption, 0, 3, 2, -1, 7); + ROW("testtest", "tt", QRegularExpression::NoPatternOption, -1, -1, 0, 0, -1); + ROW("testtest", "tt", QRegularExpression::NoPatternOption, -1, -1, 0, 1, -1); + ROW("testtest", "tt", QRegularExpression::NoPatternOption, -1, -1, 0, 2, -1); + ROW("testtest", "tt", QRegularExpression::NoPatternOption, -1, -1, 0, 3, 3); + ROW("testtest", "tt", QRegularExpression::NoPatternOption, -1, -1, 0, 4, 3); + ROW("testtest", "tt", QRegularExpression::NoPatternOption, -2, -1, 0, 0, -1); + ROW("testtest", "tt", QRegularExpression::NoPatternOption, -3, -1, 0, 0, -1); + ROW("testtest", "tt", QRegularExpression::NoPatternOption, -4, -1, 0, 0, -1); + ROW("testtest", "tt", QRegularExpression::NoPatternOption, -5, 3, 1, -1, 3); + + ROW("testtest", "(?<=t)e", QRegularExpression::NoPatternOption, 1, 1, 1, -1, 5); // the count is 1 because in the test we _cut_ the string before the lookbehind + ROW("testtest", "(?<=t)e", QRegularExpression::NoPatternOption, 2, 5, 1, -1, 5); + ROW("testtest", "(?<=t)e", QRegularExpression::NoPatternOption, 3, 5, 1, -1, 5); + ROW("testtest", "(?<=t)e", QRegularExpression::NoPatternOption, 4, 5, 1, -1, 5); + ROW("testtest", "(?<=t)e", QRegularExpression::NoPatternOption, 5, 5, 0, -1, 5); // the count is 0 because in the test we _cut_ the string before the lookbehind + ROW("testtest", "(?<=t)e", QRegularExpression::NoPatternOption, 6, -1, 0, -1, 5); + +#undef ROW +} + +template <typename String> +void tst_QStringApiSymmetry::indexOf_contains_lastIndexOf_count_regexp_impl() const +{ + QFETCH(QString, subject); + QFETCH(QRegularExpression, regexp); + QFETCH(qsizetype, leftFrom); + QFETCH(qsizetype, indexOf); + QFETCH(qsizetype, count); + QFETCH(qsizetype, rightFrom); + QFETCH(qsizetype, lastIndexOf); + + // indexOf + String s = subject; + qsizetype result = s.indexOf(regexp, leftFrom); + QCOMPARE(result, indexOf); + + // contains + if (result >= 0) + QVERIFY(s.contains(regexp)); + else if (leftFrom == 0) + QVERIFY(!s.contains(regexp)); + + // count + if (leftFrom >= 0) + QCOMPARE(s.mid(leftFrom).count(regexp), count); + else + QCOMPARE(s.mid(leftFrom + s.size()).count(regexp), count); + + // lastIndexOf + result = s.lastIndexOf(regexp, rightFrom); + QCOMPARE(result, lastIndexOf); +} + QTEST_APPLESS_MAIN(tst_QStringApiSymmetry) #include "tst_qstringapisymmetry.moc" |