diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp index d1efd2c35ae..7fc783cea56 100644 --- a/src/corelib/text/qbytearray.cpp +++ b/src/corelib/text/qbytearray.cpp @@ -2523,8 +2523,11 @@ static inline qsizetype lastIndexOfCharHelper(QByteArrayView haystack, qsizetype qsizetype QtPrivate::lastIndexOf(QByteArrayView haystack, qsizetype from, QByteArrayView needle) noexcept { - if (haystack.isEmpty()) - return !needle.size() ? 0 : -1; + if (haystack.isEmpty()) { + if (needle.isEmpty() && from == 0) + return 0; + return -1; + } const auto ol = needle.size(); if (ol == 1) return lastIndexOfCharHelper(haystack, from, needle.front()); @@ -2537,8 +2540,30 @@ qsizetype QtPrivate::lastIndexOf(QByteArrayView haystack, qsizetype from, QByteA Returns the index position of the start of the last occurrence of the sequence of bytes viewed by \a bv in this byte array, searching backward - from index position \a from. If \a from is -1 (the default), the search - starts from the end of the byte array. Returns -1 if no match is found. + from index position \a from. If \a from is -1, the search starts at + the last character; if \a from is -2, at the next to last character + and so on. Returns -1 if no match is found. + + Example: + \snippet code/src_corelib_text_qbytearray.cpp 23 + + \note When searching for a 0-length \a bv, the match at the end of + the data is excluded from the search by a negative \a from, even + though \c{-1} is normally thought of as searching from the end of + the byte array: the match at the end is \e after the last character, so + it is excluded. To include such a final empty match, either give a + positive value for \a from or omit the \a from parameter entirely. + + \sa indexOf(), contains(), count() +*/ + +/*! \fn qsizetype QByteArray::lastIndexOf(QByteArrayView bv) const + \since 6.2 + \overload + + Returns the index position of the start of the last occurrence of the + sequence of bytes viewed by \a bv in this byte array, searching backward + from the end of the byte array. Returns -1 if no match is found. Example: \snippet code/src_corelib_text_qbytearray.cpp 23 @@ -2577,6 +2602,9 @@ static inline qsizetype countCharHelper(QByteArrayView haystack, char needle) no qsizetype QtPrivate::count(QByteArrayView haystack, QByteArrayView needle) noexcept { + if (needle.size() == 0) + return haystack.size() + 1; + if (needle.size() == 1) return countCharHelper(haystack, needle[0]); diff --git a/src/corelib/text/qbytearray.h b/src/corelib/text/qbytearray.h index 10fa1e68ba1..4f29018f324 100644 --- a/src/corelib/text/qbytearray.h +++ b/src/corelib/text/qbytearray.h @@ -161,7 +161,9 @@ public: { return QtPrivate::findByteArray(qToByteArrayViewIgnoringNull(*this), from, bv); } qsizetype lastIndexOf(char c, qsizetype from = -1) const; - qsizetype lastIndexOf(QByteArrayView bv, qsizetype from = -1) const + qsizetype lastIndexOf(QByteArrayView bv) const + { return lastIndexOf(bv, size()); } + qsizetype lastIndexOf(QByteArrayView bv, qsizetype from) const { return QtPrivate::lastIndexOf(qToByteArrayViewIgnoringNull(*this), from, bv); } inline bool contains(char c) const; diff --git a/src/corelib/text/qbytearrayview.h b/src/corelib/text/qbytearrayview.h index 1dfc65b4c4c..18248264373 100644 --- a/src/corelib/text/qbytearrayview.h +++ b/src/corelib/text/qbytearrayview.h @@ -263,7 +263,9 @@ public: [[nodiscard]] bool contains(char c) const noexcept { return indexOf(c) != qsizetype(-1); } - [[nodiscard]] qsizetype lastIndexOf(QByteArrayView a, qsizetype from = -1) const noexcept + [[nodiscard]] qsizetype lastIndexOf(QByteArrayView a) const noexcept + { return lastIndexOf(a, size()); } + [[nodiscard]] qsizetype lastIndexOf(QByteArrayView a, qsizetype from) const noexcept { return QtPrivate::lastIndexOf(*this, from, a); } [[nodiscard]] qsizetype lastIndexOf(char ch, qsizetype from = -1) const noexcept { return QtPrivate::lastIndexOf(*this, from, QByteArrayView(&ch, 1)); } diff --git a/src/corelib/text/qbytearrayview.qdoc b/src/corelib/text/qbytearrayview.qdoc index 00423995a95..d52668af9b9 100644 --- a/src/corelib/text/qbytearrayview.qdoc +++ b/src/corelib/text/qbytearrayview.qdoc @@ -681,14 +681,35 @@ */ /*! - \fn qsizetype QByteArrayView::lastIndexOf(QByteArrayView bv, qsizetype from = -1) const + \fn qsizetype QByteArrayView::lastIndexOf(QByteArrayView bv, qsizetype from) const \fn qsizetype QByteArrayView::lastIndexOf(char ch, qsizetype from = -1) const Returns the index position of either the start of the last occurrence of the sequence of bytes viewed by \a bv or the last occurrence of byte \a ch, - respectively, in this byte array view, searching forward from index position - \a from. If \a from is -1 (the default), the search starts from the end of the - byte array view. Returns -1 if no match is found. + respectively, in this byte array view, searching backward from index position + \a from. If \a from is -1, the search starts at the last character; + if \a from is -2, at the next to last character and so on. + Returns -1 if no match is found. + + \note When searching for a 0-length \a bv, the match at the end of + the data is excluded from the search by a negative \a from, even + though \c{-1} is normally thought of as searching from the end of + the view: the match at the end is \e after the last character, so + it is excluded. To include such a final empty match, either give a + positive value for \a from or omit the \a from parameter entirely. + + \sa indexOf(), contains() +*/ + +/*! + \fn qsizetype QByteArrayView::lastIndexOf(QByteArrayView bv) const + \since 6.2 + \overload + + Returns the index position of the start of the last + occurrence of the sequence of bytes viewed by \a bv in this byte + array view, searching backward from the end of this byte array + view. Returns -1 if no match is found. \sa indexOf(), contains() */ diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index ffc8925ee18..f929d20c9ef 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -4012,7 +4012,7 @@ qsizetype QString::indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) con /*! Returns the index position of the last occurrence of the string \a str in this string, searching backward from index position \a - from. If \a from is -1 (default), the search starts at the last + from. If \a from is -1, the search starts at the last character; if \a from is -2, at the next to last character and so on. Returns -1 if \a str is not found. @@ -4023,6 +4023,13 @@ qsizetype QString::indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) con \snippet qstring/main.cpp 29 + \note When searching for a 0-length \a str, the match at the end of + the data is excluded from the search by a negative \a from, even + though \c{-1} is normally thought of as searching from the end of the + string: the match at the end is \e after the last character, so it is + excluded. To include such a final empty match, either give a positive + value for \a from or omit the \a from parameter entirely. + \sa indexOf(), contains(), count() */ qsizetype QString::lastIndexOf(const QString &str, qsizetype from, Qt::CaseSensitivity cs) const @@ -4030,6 +4037,25 @@ qsizetype QString::lastIndexOf(const QString &str, qsizetype from, Qt::CaseSensi return QtPrivate::lastIndexOf(QStringView(*this), from, str, cs); } +/*! + \fn qsizetype QString::lastIndexOf(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const + \since 6.2 + \overload lastIndexOf() + + Returns the index position of the last occurrence of the string \a + str in this string, searching backward from index position \a + from. Returns -1 if \a str is not found. + + If \a cs is Qt::CaseSensitive (default), the search is case + sensitive; otherwise the search is case insensitive. + + Example: + + \snippet qstring/main.cpp 29 + + \sa indexOf(), contains(), count() +*/ + #endif // QT_STRINGVIEW_LEVEL < 2 /*! @@ -4038,7 +4064,7 @@ qsizetype QString::lastIndexOf(const QString &str, qsizetype from, Qt::CaseSensi Returns the index position of the last occurrence of the string \a str in this string, searching backward from index position \a - from. If \a from is -1 (default), the search starts at the last + from. If \a from is -1, the search starts at the last character; if \a from is -2, at the next to last character and so on. Returns -1 if \a str is not found. @@ -4049,6 +4075,13 @@ qsizetype QString::lastIndexOf(const QString &str, qsizetype from, Qt::CaseSensi \snippet qstring/main.cpp 29 + \note When searching for a 0-length \a str, the match at the end of + the data is excluded from the search by a negative \a from, even + though \c{-1} is normally thought of as searching from the end of the + string: the match at the end is \e after the last character, so it is + excluded. To include such a final empty match, either give a positive + value for \a from or omit the \a from parameter entirely. + \sa indexOf(), contains(), count() */ qsizetype QString::lastIndexOf(QLatin1String str, qsizetype from, Qt::CaseSensitivity cs) const @@ -4056,6 +4089,25 @@ qsizetype QString::lastIndexOf(QLatin1String str, qsizetype from, Qt::CaseSensit return QtPrivate::lastIndexOf(*this, from, str, cs); } +/*! + \fn qsizetype QString::lastIndexOf(QLatin1String str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const + \since 6.2 + \overload lastIndexOf() + + Returns the index position of the last occurrence of the string \a + str in this string, searching backward from index position \a + from. Returns -1 if \a str is not found. + + If \a cs is Qt::CaseSensitive (default), the search is case + sensitive; otherwise the search is case insensitive. + + Example: + + \snippet qstring/main.cpp 29 + + \sa indexOf(), contains(), count() +*/ + /*! \overload lastIndexOf() @@ -4074,16 +4126,37 @@ qsizetype QString::lastIndexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) Returns the index position of the last occurrence of the string view \a str in this string, searching backward from index position \a - from. If \a from is -1 (default), the search starts at the last + from. If \a from is -1, the search starts at the last character; if \a from is -2, at the next to last character and so on. Returns -1 if \a str is not found. If \a cs is Qt::CaseSensitive (default), the search is case sensitive; otherwise the search is case insensitive. + \note When searching for a 0-length \a str, the match at the end of + the data is excluded from the search by a negative \a from, even + though \c{-1} is normally thought of as searching from the end of the + string: the match at the end is \e after the last character, so it is + excluded. To include such a final empty match, either give a positive + value for \a from or omit the \a from parameter entirely. + \sa indexOf(), contains(), count() */ +/*! + \fn qsizetype QString::lastIndexOf(QStringView str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const + \since 6.2 + \overload lastIndexOf() + + Returns the index position of the last occurrence of the string view \a + str in this string, searching backward from index position \a + from. Returns -1 if \a str is not found. + + If \a cs is Qt::CaseSensitive (default), the search is case + sensitive; otherwise the search is case insensitive. + + \sa indexOf(), contains(), count() +*/ #if QT_CONFIG(regularexpression) struct QStringCapture @@ -4356,7 +4429,9 @@ qsizetype QString::indexOf(const QRegularExpression &re, qsizetype from, QRegula Returns the index position of the last match of the regular expression \a re in the string, which starts before the index - position \a from. Returns -1 if \a re didn't match anywhere. + position \a from. If \a from is -1, the search starts at the last + character; if \a from is -2, at the next to last character and so + on. 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 @@ -4369,6 +4444,14 @@ qsizetype QString::indexOf(const QRegularExpression &re, qsizetype from, QRegula \note Due to how the regular expression matching algorithm works, this function will actually match repeatedly from the beginning of the string until the position \a from is reached. + + \note When searching for a regular expression \a re that may match + 0 characters, the match at the end of the data is excluded from the + search by a negative \a from, even though \c{-1} is normally + thought of as searching from the end of the string: the match at + the end is \e after the last character, so it is excluded. To + include such a final empty match, either give a positive value for + \a from or omit the \a from parameter entirely. */ qsizetype QString::lastIndexOf(const QRegularExpression &re, qsizetype from, QRegularExpressionMatch *rmatch) const { @@ -4377,13 +4460,13 @@ qsizetype QString::lastIndexOf(const QRegularExpression &re, qsizetype from, QRe return -1; } - qsizetype endpos = (from < 0) ? (size() + from + 1) : (from); + qsizetype endpos = (from < 0) ? (size() + from + 1) : (from + 1); QRegularExpressionMatchIterator iterator = re.globalMatch(*this); qsizetype lastIndex = -1; while (iterator.hasNext()) { QRegularExpressionMatch match = iterator.next(); qsizetype start = match.capturedStart(); - if (start <= endpos) { + if (start < endpos) { lastIndex = start; if (rmatch) *rmatch = std::move(match); @@ -4395,6 +4478,27 @@ qsizetype QString::lastIndexOf(const QRegularExpression &re, qsizetype from, QRe return lastIndex; } +/*! + \fn qsizetype QString::lastIndexOf(const QRegularExpression &re, QRegularExpressionMatch *rmatch = nullptr) const + \since 6.2 + \overload lastIndexOf() + + Returns the index position of the last match of the regular + expression \a re in the string. 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. + + Example: + + \snippet qstring/main.cpp 94 + + \note Due to how the regular expression matching algorithm works, + this function will actually match repeatedly from the beginning of + the string until the end of the string is reached. +*/ + /*! \since 5.1 @@ -9157,16 +9261,38 @@ QString &QString::setRawData(const QChar *unicode, qsizetype size) string, searching backward from index position \a from. Returns -1 if \a str is not found. - If \a from is -1 (default), the search starts at the last character; + If \a from is -1, the search starts at the last character; if \a from is -2, at the next to last character and so on. If \a cs is Qt::CaseSensitive (default), the search is case sensitive; otherwise the search is case insensitive. + \note When searching for a 0-length \a str or \a l1, the match at + the end of the data is excluded from the search by a negative \a + from, even though \c{-1} is normally thought of as searching from + the end of the string: the match at the end is \e after the last + character, so it is excluded. To include such a final empty match, + either give a positive value for \a from or omit the \a from + parameter entirely. + \sa indexOf(), QStringView::lastIndexOf(), QStringView::indexOf(), QString::indexOf() */ +/*! + \fn qsizetype QLatin1String::lastIndexOf(QStringView str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const + \fn qsizetype QLatin1String::lastIndexOf(QLatin1String l1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const + \since 6.2 + \overload lastIndexOf() + + Returns the index position of the last occurrence of the + string-view \a str or Latin-1 string \a l1, respectively, in this + Latin-1 string. Returns -1 if \a str is not found. + + If \a cs is Qt::CaseSensitive (default), the search is case + sensitive; otherwise the search is case insensitive. +*/ + /*! \fn qsizetype QLatin1String::lastIndexOf(QLatin1Char ch, qsizetype from, Qt::CaseSensitivity cs) const \since 6.3 @@ -10309,7 +10435,7 @@ static qsizetype qLastIndexOf(Haystack haystack0, qsizetype from, if (from == l && sl == 0) return from; const qsizetype delta = l - sl; - if (std::size_t(from) >= std::size_t(l) || delta < 0) + if (std::size_t(from) > std::size_t(l) || delta < 0) return -1; if (from > delta) from = delta; @@ -10497,13 +10623,13 @@ qsizetype QtPrivate::lastIndexOf(QStringView haystack, const QRegularExpression return -1; } - qsizetype endpos = (from < 0) ? (haystack.size() + from + 1) : (from); + qsizetype endpos = (from < 0) ? (haystack.size() + from + 1) : (from + 1); QRegularExpressionMatchIterator iterator = re.globalMatch(haystack); qsizetype lastIndex = -1; while (iterator.hasNext()) { QRegularExpressionMatch match = iterator.next(); qsizetype start = match.capturedStart(); - if (start <= endpos) { + if (start < endpos) { lastIndex = start; if (rmatch) *rmatch = std::move(match); diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h index 75ba4859987..b2231a239be 100644 --- a/src/corelib/text/qstring.h +++ b/src/corelib/text/qstring.h @@ -161,9 +161,13 @@ public: [[nodiscard]] inline bool contains(QLatin1Char c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept { char ch = c.toLatin1(); return indexOf(QLatin1String(&ch, 1), 0, cs) != -1; } - [[nodiscard]] qsizetype lastIndexOf(QStringView s, qsizetype from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept + [[nodiscard]] qsizetype lastIndexOf(QStringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept + { return lastIndexOf(s, size(), cs); } + [[nodiscard]] qsizetype lastIndexOf(QStringView s, qsizetype from, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept { return QtPrivate::lastIndexOf(*this, from, s, cs); } - [[nodiscard]] qsizetype lastIndexOf(QLatin1String s, qsizetype from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept + [[nodiscard]] qsizetype lastIndexOf(QLatin1String s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept + { return lastIndexOf(s, size(), cs); } + [[nodiscard]] qsizetype lastIndexOf(QLatin1String s, qsizetype from, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept { return QtPrivate::lastIndexOf(*this, from, s, cs); } [[nodiscard]] qsizetype lastIndexOf(QChar c, qsizetype from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept { return QtPrivate::lastIndexOf(*this, from, QStringView(&c, 1), cs); } @@ -347,6 +351,8 @@ qsizetype QStringView::indexOf(QLatin1String s, qsizetype from, Qt::CaseSensitiv { return QtPrivate::findString(*this, from, s, cs); } bool QStringView::contains(QLatin1String s, Qt::CaseSensitivity cs) const noexcept { return indexOf(s, 0, cs) != qsizetype(-1); } +qsizetype QStringView::lastIndexOf(QLatin1String s, Qt::CaseSensitivity cs) const noexcept +{ return QtPrivate::lastIndexOf(*this, size(), s, cs); } qsizetype QStringView::lastIndexOf(QLatin1String s, qsizetype from, Qt::CaseSensitivity cs) const noexcept { return QtPrivate::lastIndexOf(*this, from, s, cs); } @@ -516,12 +522,18 @@ public: [[nodiscard]] qsizetype indexOf(QStringView s, qsizetype from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept { return QtPrivate::findString(*this, from, s, cs); } [[nodiscard]] qsizetype lastIndexOf(QChar c, qsizetype from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; - [[nodiscard]] qsizetype lastIndexOf(QLatin1String s, qsizetype from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; + [[nodiscard]] qsizetype lastIndexOf(QLatin1String s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const + { return lastIndexOf(s, size(), cs); } + [[nodiscard]] qsizetype lastIndexOf(QLatin1String s, qsizetype from, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; #if QT_STRINGVIEW_LEVEL < 2 - [[nodiscard]] qsizetype lastIndexOf(const QString &s, qsizetype from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; + [[nodiscard]] qsizetype lastIndexOf(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const + { return lastIndexOf(s, size(), cs); } + [[nodiscard]] qsizetype lastIndexOf(const QString &s, qsizetype from, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; #endif - [[nodiscard]] qsizetype lastIndexOf(QStringView s, qsizetype from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept + [[nodiscard]] qsizetype lastIndexOf(QStringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept + { return lastIndexOf(s, size(), cs); } + [[nodiscard]] qsizetype lastIndexOf(QStringView s, qsizetype from, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept { return QtPrivate::lastIndexOf(*this, from, s, cs); } [[nodiscard]] inline bool contains(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; @@ -537,7 +549,15 @@ public: #if QT_CONFIG(regularexpression) [[nodiscard]] qsizetype indexOf(const QRegularExpression &re, qsizetype from = 0, QRegularExpressionMatch *rmatch = nullptr) const; - [[nodiscard]] qsizetype lastIndexOf(const QRegularExpression &re, qsizetype from = -1, +#ifdef Q_QDOC + [[nodiscard]] qsizetype lastIndexOf(const QRegularExpression &re, QRegularExpressionMatch *rmatch = nullptr) const; +#else + // prevent an ambiguity when called like this: lastIndexOf(re, 0) + template , bool> = false> + [[nodiscard]] qsizetype lastIndexOf(const QRegularExpression &re, T *rmatch = nullptr) const + { return lastIndexOf(re, size(), rmatch); } +#endif + [[nodiscard]] qsizetype lastIndexOf(const QRegularExpression &re, qsizetype from, QRegularExpressionMatch *rmatch = nullptr) const; [[nodiscard]] bool contains(const QRegularExpression &re, QRegularExpressionMatch *rmatch = nullptr) const; [[nodiscard]] qsizetype count(const QRegularExpression &re) const; diff --git a/src/corelib/text/qstringview.cpp b/src/corelib/text/qstringview.cpp index d1b01934ffc..dc7ff5a86bf 100644 --- a/src/corelib/text/qstringview.cpp +++ b/src/corelib/text/qstringview.cpp @@ -880,13 +880,38 @@ QT_BEGIN_NAMESPACE Returns the index position of the last occurrence of the string view \a str, Latin-1 string \a l1, or character \a ch, respectively, in this string view, - searching backward from index position \a from. If \a from is -1 (default), + searching backward from index position \a from. If \a from is -1, the search starts at the last character; if \a from is -2, at the next to last character and so on. Returns -1 if \a str is not found. If \a cs is Qt::CaseSensitive (default), the search is case sensitive; otherwise the search is case insensitive. + \note When searching for a 0-length \a str or \a l1, the match at + the end of the data is excluded from the search by a negative \a + from, even though \c{-1} is normally thought of as searching from + the end of the string view: the match at the end is \e after the + last character, so it is excluded. To include such a final empty + match, either give a positive value for \a from or omit the \a from + parameter entirely. + + \sa QString::lastIndexOf() +*/ + +/*! + \fn qsizetype QStringView::lastIndexOf(QStringView str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const + \fn qsizetype QStringView::lastIndexOf(QLatin1String l1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const + \since 6.2 + \overload lastIndexOf() + + Returns the index position of the last occurrence of the string view \a str + or Latin-1 string \a l1, respectively, in this string view, + searching backward from the last character of this string view. + Returns -1 if \a str is not found. + + If \a cs is Qt::CaseSensitive (default), the search is case + sensitive; otherwise the search is case insensitive. + \sa QString::lastIndexOf() */ @@ -912,6 +937,33 @@ QT_BEGIN_NAMESPACE \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. If \a from is -1, the search starts at the last + character; if \a from is -2, at the next to last character and so + on. 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. + + \note When searching for a regular expression \a re that may match + 0 characters, the match at the end of the data is excluded from the + search by a negative \a from, even though \c{-1} is normally + thought of as searching from the end of the string view: the match + at the end is \e after the last character, so it is excluded. To + include such a final empty match, either give a positive value for + \a from or omit the \a from parameter entirely. +*/ + +/*! + \fn qsizetype QStringView::lastIndexOf(const QRegularExpression &re, QRegularExpressionMatch *rmatch = nullptr) const + \since 6.2 + 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. @@ -919,6 +971,10 @@ QT_BEGIN_NAMESPACE 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 end of the string view is reached. */ /*! diff --git a/src/corelib/text/qstringview.h b/src/corelib/text/qstringview.h index e34418e9560..5c204fb7ddd 100644 --- a/src/corelib/text/qstringview.h +++ b/src/corelib/text/qstringview.h @@ -344,16 +344,29 @@ public: [[nodiscard]] qsizetype lastIndexOf(QChar c, qsizetype from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept { return QtPrivate::lastIndexOf(*this, from, QStringView(&c, 1), cs); } - [[nodiscard]] qsizetype lastIndexOf(QStringView s, qsizetype from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept + [[nodiscard]] qsizetype lastIndexOf(QStringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept + { return lastIndexOf(s, size(), cs); } + [[nodiscard]] qsizetype lastIndexOf(QStringView s, qsizetype from, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept { return QtPrivate::lastIndexOf(*this, from, s, cs); } - [[nodiscard]] inline qsizetype lastIndexOf(QLatin1String s, qsizetype from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept; + [[nodiscard]] inline qsizetype lastIndexOf(QLatin1String s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept; + [[nodiscard]] inline qsizetype lastIndexOf(QLatin1String s, qsizetype from, 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 +#ifdef Q_QDOC + [[nodiscard]] qsizetype lastIndexOf(const QRegularExpression &re, QRegularExpressionMatch *rmatch = nullptr) const; +#else + // prevent an ambiguity when called like this: lastIndexOf(re, 0) + template , bool> = false> + [[nodiscard]] qsizetype lastIndexOf(const QRegularExpression &re, T *rmatch = nullptr) const + { + return QtPrivate::lastIndexOf(*this, re, size(), rmatch); + } +#endif + [[nodiscard]] qsizetype lastIndexOf(const QRegularExpression &re, qsizetype from, QRegularExpressionMatch *rmatch = nullptr) const { return QtPrivate::lastIndexOf(*this, re, from, rmatch); } diff --git a/tests/auto/corelib/text/qbytearrayapisymmetry/tst_qbytearrayapisymmetry.cpp b/tests/auto/corelib/text/qbytearrayapisymmetry/tst_qbytearrayapisymmetry.cpp index 5f181647af5..4d419dd0d3f 100644 --- a/tests/auto/corelib/text/qbytearrayapisymmetry/tst_qbytearrayapisymmetry.cpp +++ b/tests/auto/corelib/text/qbytearrayapisymmetry/tst_qbytearrayapisymmetry.cpp @@ -430,10 +430,14 @@ void tst_QByteArrayApiSymmetry::lastIndexOf_data() QTest::newRow("null from 0") << QByteArray() << QByteArray("x") << 0 << -1; QTest::newRow("null from -1") << QByteArray() << QByteArray("x") << -1 << -1; QTest::newRow("null from 1") << QByteArray() << QByteArray("x") << 1 << -1; - QTest::newRow("null-in-null") << QByteArray() << QByteArray() << -1 << 0; - QTest::newRow("empty-in-null") << QByteArray() << QByteArray("") << -1 << 0; - QTest::newRow("null-in-empty") << QByteArray("") << QByteArray() << -1 << 0; - QTest::newRow("empty-in-empty") << QByteArray("") << QByteArray("") << -1 << 0; + QTest::newRow("null-in-null-off--1") << QByteArray() << QByteArray() << -1 << -1; + QTest::newRow("null-in-null-off-0") << QByteArray() << QByteArray() << 0 << 0; + QTest::newRow("empty-in-null-off--1") << QByteArray() << QByteArray("") << -1 << -1; + QTest::newRow("empty-in-null-off-0") << QByteArray() << QByteArray("") << 0 << 0; + QTest::newRow("null-in-empty-off--1") << QByteArray("") << QByteArray() << -1 << -1; + QTest::newRow("null-in-empty-off-0") << QByteArray("") << QByteArray() << 0 << 0; + QTest::newRow("empty-in-empty-off--1") << QByteArray("") << QByteArray("") << -1 << -1; + QTest::newRow("empty-in-empty-off-0") << QByteArray("") << QByteArray("") << 0 << 0; QTest::newRow("empty in abc from 0") << abc << QByteArray() << 0 << 0; QTest::newRow("empty in abc from 2") << abc << QByteArray() << 2 << 2; QTest::newRow("empty in abc from 5") @@ -462,7 +466,7 @@ void tst_QByteArrayApiSymmetry::lastIndexOf_impl() if (needle.size() == 1) QCOMPARE(haystack.lastIndexOf(needle.at(0), startpos), expected); - if (startpos == -1) { + if (startpos == haystack.size()) { QCOMPARE(haystack.lastIndexOf(needle), expected); if (!hasNull) QCOMPARE(haystack.lastIndexOf(needle.data()), expected); diff --git a/tests/auto/corelib/text/qstring/tst_qstring.cpp b/tests/auto/corelib/text/qstring/tst_qstring.cpp index f0ed8f3e6d0..813e2470134 100644 --- a/tests/auto/corelib/text/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/text/qstring/tst_qstring.cpp @@ -1728,7 +1728,7 @@ void tst_QString::lastIndexOf_data() QTest::newRow("14") << a << "A" << -1*int(a.size()) << 0 << true; QTest::newRow("15") << a << "efg" << 0 << -1 << false; - QTest::newRow("16") << a << "efg" << int(a.size()) << -1 << false; + QTest::newRow("16") << a << "efg" << int(a.size()) << 12 << false; QTest::newRow("17") << a << "efg" << -1 * int(a.size()) << -1 << false; QTest::newRow("19") << a << "efg" << int(a.size()) - 1 << 12 << false; QTest::newRow("20") << a << "efg" << 12 << 12 << false; @@ -1797,7 +1797,7 @@ void tst_QString::lastIndexOf() QCOMPARE(haystack.lastIndexOf(view, from), expected); QCOMPARE(haystack.lastIndexOf(needle.toLatin1(), from), expected); QCOMPARE(haystack.lastIndexOf(needle.toLatin1().data(), from), expected); - if (from == -1) { + if (from == haystack.size()) { QCOMPARE(haystack.lastIndexOf(needle), expected); QCOMPARE(haystack.lastIndexOf(view), expected); QCOMPARE(haystack.lastIndexOf(needle.toLatin1()), expected); diff --git a/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp b/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp index 3f2838e2b79..88ccc8d3bfa 100644 --- a/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp +++ b/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp @@ -2595,7 +2595,7 @@ void tst_QStringApiSymmetry::lastIndexOf_data(bool rhsHasVariableLength) if (rhsHasVariableLength) { ROW(ABCDEFGHIEfGEFG, efg, 0, -1, -1); - ROW(ABCDEFGHIEfGEFG, efg, 15, -1, -1); + ROW(ABCDEFGHIEfGEFG, efg, 15, -1, 12); ROW(ABCDEFGHIEfGEFG, efg, -15, -1, -1); ROW(ABCDEFGHIEfGEFG, efg, 14, -1, 12); ROW(ABCDEFGHIEfGEFG, efg, 12, -1, 12); @@ -2657,15 +2657,32 @@ void tst_QStringApiSymmetry::indexOf_contains_lastIndexOf_count_regexp_data() << 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("", "", QRegularExpression::NoPatternOption, 0, 0, 1, -1, -1); + ROW("", "", QRegularExpression::NoPatternOption, 0, 0, 1, 0, 0); + ROW("test", "", QRegularExpression::NoPatternOption, 0, 0, 5, -1, 3); + ROW("test", "", QRegularExpression::NoPatternOption, 0, 0, 5, -2, 2); + ROW("test", "", QRegularExpression::NoPatternOption, 0, 0, 5, -3, 1); + ROW("test", "", QRegularExpression::NoPatternOption, 0, 0, 5, -4, 0); + ROW("test", "", QRegularExpression::NoPatternOption, 0, 0, 5, -5, -1); + ROW("test", "", QRegularExpression::NoPatternOption, 0, 0, 5, 0, 0); + ROW("test", "", QRegularExpression::NoPatternOption, 0, 0, 5, 1, 1); + ROW("test", "", QRegularExpression::NoPatternOption, 0, 0, 5, 2, 2); + ROW("test", "", QRegularExpression::NoPatternOption, 0, 0, 5, 3, 3); + ROW("test", "", QRegularExpression::NoPatternOption, 0, 0, 5, 4, 4); + ROW("", "^", QRegularExpression::NoPatternOption, 0, 0, 1, -1, -1); + ROW("", "^", QRegularExpression::NoPatternOption, 0, 0, 1, 0, 0); + ROW("", "$", QRegularExpression::NoPatternOption, 0, 0, 1, -1, -1); + ROW("", "$", QRegularExpression::NoPatternOption, 0, 0, 1, 0, 0); + ROW("", "^$", QRegularExpression::NoPatternOption, 0, 0, 1, -1, -1); + ROW("", "^$", QRegularExpression::NoPatternOption, 0, 0, 1, 0, 0); ROW("", "x", QRegularExpression::NoPatternOption, 0, -1, 0, -1, -1); + ROW("", "x", QRegularExpression::NoPatternOption, 0, -1, 0, 0, -1); ROW("", "^x", QRegularExpression::NoPatternOption, 0, -1, 0, -1, -1); + ROW("", "^x", QRegularExpression::NoPatternOption, 0, -1, 0, 0, -1); ROW("", "x$", QRegularExpression::NoPatternOption, 0, -1, 0, -1, -1); + ROW("", "x$", QRegularExpression::NoPatternOption, 0, -1, 0, 0, -1); ROW("", "^x$", QRegularExpression::NoPatternOption, 0, -1, 0, -1, -1); + ROW("", "^x$", QRegularExpression::NoPatternOption, 0, -1, 0, 0, -1); ROW("test", "e", QRegularExpression::NoPatternOption, 0, 1, 1, -1, 1); ROW("test", "e", QRegularExpression::NoPatternOption, 0, 1, 1, -2, 1); @@ -2686,8 +2703,11 @@ void tst_QStringApiSymmetry::indexOf_contains_lastIndexOf_count_regexp_data() ROW("test", "(? @@ -2825,6 +2851,10 @@ void tst_QStringApiSymmetry::indexOf_contains_lastIndexOf_count_regexp_impl() co // lastIndexOf result = s.lastIndexOf(regexp, rightFrom); QCOMPARE(result, lastIndexOf); + if (rightFrom == s.size()) { + result = s.lastIndexOf(regexp); + QCOMPARE(result, lastIndexOf); + } } QTEST_APPLESS_MAIN(tst_QStringApiSymmetry) diff --git a/tests/auto/corelib/tools/collections/tst_collections.cpp b/tests/auto/corelib/tools/collections/tst_collections.cpp index 5b26ae5faa0..c653afa68e3 100644 --- a/tests/auto/corelib/tools/collections/tst_collections.cpp +++ b/tests/auto/corelib/tools/collections/tst_collections.cpp @@ -978,6 +978,16 @@ void tst_Collections::byteArray() QVERIFY(hello.indexOf('l',2) == 2); QVERIFY(hello.indexOf('l',3) == 3); + QByteArray empty; + QCOMPARE(empty.indexOf("x"), -1); + QCOMPARE(empty.lastIndexOf("x"), -1); + QCOMPARE(empty.lastIndexOf("x", 0), -1); + QCOMPARE(empty.count("x"), 0); + QCOMPARE(empty.indexOf(""), 0); + QCOMPARE(empty.lastIndexOf(""), 0); + QCOMPARE(empty.lastIndexOf("", -1), -1); + QCOMPARE(empty.count(""), 1); + QByteArray large = "000 100 200 300 400 500 600 700 800 900"; QVERIFY(large.indexOf("700") == 28); @@ -1715,6 +1725,16 @@ void tst_Collections::qstring() QVERIFY(hello.indexOf('l',2) == 2); QVERIFY(hello.indexOf('l',3) == 3); + QString empty; + QCOMPARE(empty.indexOf("x"), -1); + QCOMPARE(empty.lastIndexOf("x"), -1); + QCOMPARE(empty.lastIndexOf("x", 0), -1); + QCOMPARE(empty.count("x"), 0); + QCOMPARE(empty.indexOf(""), 0); + QCOMPARE(empty.lastIndexOf(""), 0); + QCOMPARE(empty.lastIndexOf("", -1), -1); + QCOMPARE(empty.count(""), 1); + QString large = "000 100 200 300 400 500 600 700 800 900"; QVERIFY(large.indexOf("700") == 28); @@ -1724,6 +1744,20 @@ void tst_Collections::qstring() QVERIFY(large.lastIndexOf("700", 28) == 28); QVERIFY(large.lastIndexOf("700", 27) == -1); + QCOMPARE(large.indexOf(""), 0); + QCOMPARE(large.indexOf(QString()), 0); + QCOMPARE(large.indexOf(QLatin1String()), 0); + QCOMPARE(large.indexOf(QStringView()), 0); + QCOMPARE(large.lastIndexOf(""), large.size()); + QCOMPARE(large.lastIndexOf("", -1), large.size() - 1); + QCOMPARE(large.lastIndexOf(QString()), large.size()); + QCOMPARE(large.lastIndexOf(QLatin1String()), large.size()); + QCOMPARE(large.lastIndexOf(QStringView()), large.size()); + QCOMPARE(large.count(""), large.size() + 1); + QCOMPARE(large.count(QString()), large.size() + 1); + QCOMPARE(large.count(QLatin1String()), large.size() + 1); + QCOMPARE(large.count(QStringView()), large.size() + 1); + QVERIFY(large.contains("200")); QVERIFY(!large.contains("201")); QVERIFY(large.contains('3'));