summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2021-06-08 16:44:26 +0200
committerGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2021-08-19 01:55:01 +0200
commit6cee204d56205e250b0675c9c6d4dd8a2367f3c4 (patch)
treedefea538f66583daf2a80b69b8f968853f45f937 /src
parent6feb28918924d80c94b6f435bc3bc981855d59d6 (diff)
QS(V)/QBA(V)/QL1S::lastIndexOf: fix the offset calculations
When trying to fix 0-length matches at the end of a QString, be83ff65c424cff1036e7da19d6175826d9f7ed9 actually introduced a regression due to how lastIndexOf interprets its `from` parameter. The "established" (=legacy) interpretation of a negative `from` is that it is supposed to indicate that we want the last match at offset `from + size()`. With the default from of -1, that means we want a match starting at most at position `size() - 1` inclusive, i.e. *at* the last position in the string. The aforementioned commit changed that, by allowing a match at position `size()` instead, and this behavioral change broke code. The problem the commit tried to fix was that empty matches *are* allowed to happen at position size(): the last match of regexp // inside the string "test" is indeed at position 4 (the regexp matches 5 times). Changing the meaning of negative from to include that last position (in general: to include position `from+size()+1` as the last valid matching position, in case of a negative `from`) has unfortunately broken client code. Therefore, we need to revert it. This patch does that, adapting the tests as necessary (drive-by: a broken #undef is removed). Reverting the patch however is not sufficient. What we are facing here is an historical API mistake that forces the default `from` (-1) to *skip* the truly last possible match; the mistake is that thre is simply no way to pass a negative `from` and obtain that match. This means that the revert will now cause code like this: str.lastIndexOf(QRE("")); // `from` defaulted to -1 NOT to return str.size(), which is counter-intuitive and wrong. Other APIs expose this inconsistency: for instance, using QRegularExpressionIterator would actually yield a last match at position str.size(). Similarly, using QString::count would return `str.size()+1`. Note that, in general, it's still possible for clients to call str.lastIndexOf(~~~, str.size()) to get the "truly last" match. This patch also tries to fix this case ("have our cake and eat it"). First and foremost, a couple of bugs in QByteArray and QString code are fixed (when dealing with 0-length needles). Second, a lastIndexOf overload is added. One overload is the "legacy" one, that will honor the pre-existing semantics of negative `from`. The new overload does NOT take a `from` parameter at all, and will actually match from the truly end (by simply calling `lastIndexOf(~~~, size())` internally). These overloads are offered for all the existing lastIndexOf() overloads, not only the ones taking QRE. This means that code simply using `lastIndexOf` without any `from` parameter get the "correct" behavior for 0-length matches, and code that specifies one gets the legacy behavior. Matches of length > 0 are not affected anyways, as they can't match at position size(). [ChangeLog][Important Behavior Changes] A regression in the behavior of the lastIndexOf() function on text-related containers and views (QString, QStringView, QByteArray, QByteArrayView, QLatin1String) has been fixed, and the behavior made consistent and more in line with user expectations. When lastIndexOf() is invoked with a negative `from` position, the last match has now to start at the last character in the container/view (before, it was at the position *past* the last character). This makes a difference when using lastIndexOf() with a needle that has 0 length (for instance an empty string, a regular expression that can match 0 characters, and so on); any other case is unaffected. To retrieve the "truly last" match, one can pass a positive `from` offset to lastIndexOf() (basically, pass `size()` as the `from` parameter). To make calls such as `text.lastIndexOf(~~~);`, that do not pass any `from` parameter, behave properly, a new lastIndexOf() overload has been added to all the text containers/views. This overload does not take a `from` parameter at all, and will search starting from one character past the end of the text, therefore returning a correct result when used with needles that may yield 0-length matches. Client code may need to be recompiled in order to use this new overload. Conversely, client code that needs to skip the "truly last" match now needs to pass -1 as the `from` parameter instead of relying on the default. Change-Id: I5e92bdcf1a57c2c3cca97b6adccf0883d00a92e5 Fixes: QTBUG-94215 Pick-to: 6.2 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/corelib/text/qbytearray.cpp36
-rw-r--r--src/corelib/text/qbytearray.h4
-rw-r--r--src/corelib/text/qbytearrayview.h4
-rw-r--r--src/corelib/text/qbytearrayview.qdoc29
-rw-r--r--src/corelib/text/qstring.cpp146
-rw-r--r--src/corelib/text/qstring.h32
-rw-r--r--src/corelib/text/qstringview.cpp58
-rw-r--r--src/corelib/text/qstringview.h19
8 files changed, 298 insertions, 30 deletions
diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp
index d1efd2c35a..7fc783cea5 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 10fa1e68ba..4f29018f32 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 1dfc65b4c4..1824826437 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 00423995a9..d52668af9b 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 ffc8925ee1..f929d20c9e 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
@@ -4057,6 +4090,25 @@ qsizetype QString::lastIndexOf(QLatin1String str, qsizetype from, Qt::CaseSensit
}
/*!
+ \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()
Returns the index position of the last occurrence of the character
@@ -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);
@@ -4396,6 +4479,27 @@ qsizetype QString::lastIndexOf(const QRegularExpression &re, qsizetype from, QRe
}
/*!
+ \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
Returns \c true if the regular expression \a re matches somewhere in this
@@ -9157,17 +9261,39 @@ 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
\overload
@@ -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 75ba485998..b2231a239b 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 <typename T = QRegularExpressionMatch, std::enable_if_t<std::is_same_v<T, QRegularExpressionMatch>, 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 d1b01934ff..dc7ff5a86b 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()
*/
@@ -914,11 +939,42 @@ QT_BEGIN_NAMESPACE
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.
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 e34418e956..5c204fb7dd 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 <typename T = QRegularExpressionMatch, std::enable_if_t<std::is_same_v<T, QRegularExpressionMatch>, 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);
}