summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/text/qregexp.cpp414
-rw-r--r--src/corelib/text/qregexp.h16
-rw-r--r--src/corelib/text/qstring.cpp195
-rw-r--r--src/corelib/text/qstringlist.cpp41
-rw-r--r--tests/auto/corelib/text/qregexp/tst_qregexp.cpp163
5 files changed, 606 insertions, 223 deletions
diff --git a/src/corelib/text/qregexp.cpp b/src/corelib/text/qregexp.cpp
index 758a3695c9..cbf827f2b8 100644
--- a/src/corelib/text/qregexp.cpp
+++ b/src/corelib/text/qregexp.cpp
@@ -4479,6 +4479,419 @@ int QRegExp::matchedLength() const
return priv->matchState.captured[1];
}
+
+/*!
+ Replaces every occurrence of this regular expression in
+ \a str with \a after and returns the result.
+
+ For regular expressions containing \l{capturing parentheses},
+ occurrences of \b{\\1}, \b{\\2}, ..., in \a after are replaced
+ with \a{rx}.cap(1), cap(2), ...
+
+ \sa indexIn(), lastIndexIn(), QRegExp::cap()
+*/
+QString QRegExp::replaceIn(const QString &str, const QString &after) const
+{
+ struct QStringCapture
+ {
+ int pos;
+ int len;
+ int no;
+ };
+
+ QRegExp rx2(*this);
+
+ if (str.isEmpty() && rx2.indexIn(str) == -1)
+ return str;
+
+ QString s(str);
+
+ int index = 0;
+ int numCaptures = rx2.captureCount();
+ int al = after.length();
+ QRegExp::CaretMode caretMode = QRegExp::CaretAtZero;
+
+ if (numCaptures > 0) {
+ const QChar *uc = after.unicode();
+ int numBackRefs = 0;
+
+ for (int i = 0; i < al - 1; i++) {
+ if (uc[i] == QLatin1Char('\\')) {
+ int no = uc[i + 1].digitValue();
+ if (no > 0 && no <= numCaptures)
+ numBackRefs++;
+ }
+ }
+
+ /*
+ This is the harder case where we have back-references.
+ */
+ if (numBackRefs > 0) {
+ QVarLengthArray<QStringCapture, 16> captures(numBackRefs);
+ int j = 0;
+
+ for (int i = 0; i < al - 1; i++) {
+ if (uc[i] == QLatin1Char('\\')) {
+ int no = uc[i + 1].digitValue();
+ if (no > 0 && no <= numCaptures) {
+ QStringCapture capture;
+ capture.pos = i;
+ capture.len = 2;
+
+ if (i < al - 2) {
+ int secondDigit = uc[i + 2].digitValue();
+ if (secondDigit != -1 && ((no * 10) + secondDigit) <= numCaptures) {
+ no = (no * 10) + secondDigit;
+ ++capture.len;
+ }
+ }
+
+ capture.no = no;
+ captures[j++] = capture;
+ }
+ }
+ }
+
+ while (index <= s.length()) {
+ index = rx2.indexIn(s, index, caretMode);
+ if (index == -1)
+ break;
+
+ QString after2(after);
+ for (j = numBackRefs - 1; j >= 0; j--) {
+ const QStringCapture &capture = captures[j];
+ after2.replace(capture.pos, capture.len, rx2.cap(capture.no));
+ }
+
+ s.replace(index, rx2.matchedLength(), after2);
+ index += after2.length();
+
+ // avoid infinite loop on 0-length matches (e.g., QRegExp("[a-z]*"))
+ if (rx2.matchedLength() == 0)
+ ++index;
+
+ caretMode = QRegExp::CaretWontMatch;
+ }
+ return s;
+ }
+ }
+
+ /*
+ This is the simple and optimized case where we don't have
+ back-references.
+ */
+ while (index != -1) {
+ struct {
+ int pos;
+ int length;
+ } replacements[2048];
+
+ int pos = 0;
+ int adjust = 0;
+ while (pos < 2047) {
+ index = rx2.indexIn(s, index, caretMode);
+ if (index == -1)
+ break;
+ int ml = rx2.matchedLength();
+ replacements[pos].pos = index;
+ replacements[pos++].length = ml;
+ index += ml;
+ adjust += al - ml;
+ // avoid infinite loop
+ if (!ml)
+ index++;
+ }
+ if (!pos)
+ break;
+ replacements[pos].pos = s.size();
+ int newlen = s.size() + adjust;
+
+ // to continue searching at the right position after we did
+ // the first round of replacements
+ if (index != -1)
+ index += adjust;
+ QString newstring;
+ newstring.reserve(newlen + 1);
+ QChar *newuc = newstring.data();
+ QChar *uc = newuc;
+ int copystart = 0;
+ int i = 0;
+ while (i < pos) {
+ int copyend = replacements[i].pos;
+ int size = copyend - copystart;
+ memcpy(static_cast<void*>(uc), static_cast<const void *>(s.constData() + copystart), size * sizeof(QChar));
+ uc += size;
+ memcpy(static_cast<void *>(uc), static_cast<const void *>(after.constData()), al * sizeof(QChar));
+ uc += al;
+ copystart = copyend + replacements[i].length;
+ i++;
+ }
+ memcpy(static_cast<void *>(uc), static_cast<const void *>(s.constData() + copystart), (s.size() - copystart) * sizeof(QChar));
+ newstring.resize(newlen);
+ s = newstring;
+ caretMode = QRegExp::CaretWontMatch;
+ }
+ return s;
+
+}
+
+
+/*!
+ \fn QString QRegExp::removeIn(const QString &str)
+
+ Removes every occurrence of this regular expression \a str, and
+ returns the result
+
+ Does the same as replaceIn(str, QString()).
+
+ \sa indexIn(), lastIndexIn(), replaceIn()
+*/
+
+
+/*!
+ \fn QString QRegExp::countIn(const QString &str)
+
+ Returns the number of times this regular expression matches
+ in \a str.
+
+ \sa indexIn(), lastIndexIn(), replaceIn()
+*/
+
+int QRegExp::countIn(const QString &str) const
+{
+ QRegExp rx2(*this);
+ int count = 0;
+ int index = -1;
+ int len = str.length();
+ while (index < len - 1) { // count overlapping matches
+ index = rx2.indexIn(str, index + 1);
+ if (index == -1)
+ break;
+ count++;
+ }
+ return count;
+}
+
+class qt_section_chunk {
+public:
+ qt_section_chunk() {}
+ qt_section_chunk(int l, QStringRef s) : length(l), string(std::move(s)) {}
+ int length;
+ QStringRef string;
+};
+
+static QString extractSections(const QVector<qt_section_chunk> &sections,
+ int start,
+ int end,
+ QString::SectionFlags flags)
+{
+ const int sectionsSize = sections.size();
+
+ if (!(flags & QString::SectionSkipEmpty)) {
+ if (start < 0)
+ start += sectionsSize;
+ if (end < 0)
+ end += sectionsSize;
+ } else {
+ int skip = 0;
+ for (int k = 0; k < sectionsSize; ++k) {
+ const qt_section_chunk &section = sections.at(k);
+ if (section.length == section.string.length())
+ skip++;
+ }
+ if (start < 0)
+ start += sectionsSize - skip;
+ if (end < 0)
+ end += sectionsSize - skip;
+ }
+ if (start >= sectionsSize || end < 0 || start > end)
+ return QString();
+
+ QString ret;
+ int x = 0;
+ int first_i = start, last_i = end;
+ for (int i = 0; x <= end && i < sectionsSize; ++i) {
+ const qt_section_chunk &section = sections.at(i);
+ const bool empty = (section.length == section.string.length());
+ if (x >= start) {
+ if (x == start)
+ first_i = i;
+ if (x == end)
+ last_i = i;
+ if (x != start)
+ ret += section.string;
+ else
+ ret += section.string.mid(section.length);
+ }
+ if (!empty || !(flags & QString::SectionSkipEmpty))
+ x++;
+ }
+
+ if ((flags & QString::SectionIncludeLeadingSep) && first_i >= 0) {
+ const qt_section_chunk &section = sections.at(first_i);
+ ret.prepend(section.string.left(section.length));
+ }
+
+ if ((flags & QString::SectionIncludeTrailingSep)
+ && last_i < sectionsSize - 1) {
+ const qt_section_chunk &section = sections.at(last_i+1);
+ ret += section.string.left(section.length);
+ }
+
+ return ret;
+}
+/*!
+ \a str is treated as a sequence of fields separated by this
+ regular expression.
+
+ \sa splitString()
+*/
+QString QRegExp::sectionIn(const QString &str, int start, int end, QString::SectionFlags flags) const
+{
+ if (str.isEmpty())
+ return str;
+
+ QRegExp sep(*this);
+ sep.setCaseSensitivity((flags & QString::SectionCaseInsensitiveSeps) ? Qt::CaseInsensitive
+ : Qt::CaseSensitive);
+
+ QVector<qt_section_chunk> sections;
+ int n = str.length(), m = 0, last_m = 0, last_len = 0;
+ while ((m = sep.indexIn(str, m)) != -1) {
+ sections.append(qt_section_chunk(last_len, QStringRef(&str, last_m, m - last_m)));
+ last_m = m;
+ last_len = sep.matchedLength();
+ m += qMax(sep.matchedLength(), 1);
+ }
+ sections.append(qt_section_chunk(last_len, QStringRef(&str, last_m, n - last_m)));
+
+ return extractSections(sections, start, end, flags);
+}
+
+/*!
+ Splits \a str into substrings wherever this regular expression
+ matches, and returns the list of those strings. If this regular
+ expression does not match anywhere in the string, split() returns a
+ single-element list containing \a str.
+
+ \sa QStringList::join(), section(), QString::split()
+*/
+QStringList QRegExp::splitString(const QString &str, Qt::SplitBehavior behavior) const
+{
+ QRegExp rx2(*this);
+ QStringList list;
+ int start = 0;
+ int extra = 0;
+ int end;
+ while ((end = rx2.indexIn(str, start + extra)) != -1) {
+ int matchedLen = rx2.matchedLength();
+ if (start != end || behavior == Qt::KeepEmptyParts)
+ list.append(str.mid(start, end - start));
+ start = end + matchedLen;
+ extra = (matchedLen == 0) ? 1 : 0;
+ }
+ if (start != str.size() || behavior == Qt::KeepEmptyParts)
+ list.append(str.mid(start, -1));
+ return list;
+}
+
+/*!
+ Splits \a str into substrings wherever this regular expression
+ matches, and returns the list of those strings. If this regular
+ expression does not match anywhere in the string, split() returns a
+ single-element list containing \a str.
+
+ \sa QStringList::join(), section(), QString::split()
+*/
+QVector<QStringRef> QRegExp::splitStringAsRef(const QString &str, Qt::SplitBehavior behavior) const
+{
+ QRegExp rx2(*this);
+ QVector<QStringRef> list;
+ int start = 0;
+ int extra = 0;
+ int end;
+ while ((end = rx2.indexIn(str, start + extra)) != -1) {
+ int matchedLen = rx2.matchedLength();
+ if (start != end || behavior == Qt::KeepEmptyParts)
+ list.append(str.midRef(start, end - start));
+ start = end + matchedLen;
+ extra = (matchedLen == 0) ? 1 : 0;
+ }
+ if (start != str.size() || behavior == Qt::KeepEmptyParts)
+ list.append(str.midRef(start, -1));
+ return list;
+}
+
+/*!
+ \fn QStringList QStringList::filter(const QRegExp &rx) const
+
+ \overload
+
+ Returns a list of all the strings that match the regular
+ expression \a rx.
+*/
+QStringList QRegExp::filterList(const QStringList &stringList) const
+{
+ QStringList res;
+ for (const QString &s : stringList) {
+ if (containedIn(s))
+ res << s;
+ }
+ return res;
+}
+
+/*!
+ Replaces every occurrence of the regexp \a rx, in each of the
+ string lists's strings, with \a after. Returns a reference to the
+ string list.
+*/
+QStringList QRegExp::replaceIn(const QStringList &stringList, const QString &after) const
+{
+ QStringList list;
+ for (const QString &s : stringList)
+ list << replaceIn(s, after);
+ return list;
+}
+
+/*!
+ Returns the index position of the first exact match of this regexp in
+ \a list, searching forward from index position \a from. Returns
+ -1 if no item matched.
+
+ \sa lastIndexIn(), contains(), exactMatch()
+*/
+int QRegExp::indexIn(const QStringList &list, int from)
+{
+ if (from < 0)
+ from = qMax(from + list.size(), 0);
+ for (int i = from; i < list.size(); ++i) {
+ if (exactMatch(list.at(i)))
+ return i;
+ }
+ return -1;
+}
+
+/*!
+ Returns the index position of the last exact match of this regexp in
+ \a list, searching backward from index position \a from. If \a
+ from is -1 (the default), the search starts at the last item.
+ Returns -1 if no item matched.
+
+ \sa indexOf(), contains(), QRegExp::exactMatch()
+*/
+int QRegExp::lastIndexIn(const QStringList &list, int from)
+{
+ if (from < 0)
+ from += list.size();
+ else if (from >= list.size())
+ from = list.size() - 1;
+ for (int i = from; i >= 0; --i) {
+ if (exactMatch(list.at(i)))
+ return i;
+ }
+ return -1;
+}
+
#ifndef QT_NO_REGEXP_CAPTURE
/*!
@@ -4637,6 +5050,7 @@ QString QRegExp::errorString()
{
return const_cast<const QRegExp *>(this)->errorString();
}
+
#endif
/*!
diff --git a/src/corelib/text/qregexp.h b/src/corelib/text/qregexp.h
index b42214f1db..d1181d6fa6 100644
--- a/src/corelib/text/qregexp.h
+++ b/src/corelib/text/qregexp.h
@@ -108,6 +108,22 @@ public:
QString errorString();
#endif
+ QString replaceIn(const QString &str, const QString &after) const;
+ QString removeIn(const QString &str) const
+ { return replaceIn(str, QString()); }
+ bool containedIn(const QString &str) const
+ { return indexIn(str) != -1; }
+ int countIn(const QString &str) const;
+ QString sectionIn(const QString &str, int start, int end, QString::SectionFlags flags) const;
+
+ QStringList splitString(const QString &str, Qt::SplitBehavior behavior = Qt::KeepEmptyParts) const;
+ QVector<QStringRef> splitStringAsRef(const QString &str, Qt::SplitBehavior behavior = Qt::KeepEmptyParts) const;
+
+ int indexIn(const QStringList &list, int from);
+ int lastIndexIn(const QStringList &list, int from);
+ QStringList replaceIn(const QStringList &stringList, const QString &after) const;
+ QStringList filterList(const QStringList &stringList) const;
+
static QString escape(const QString &str);
friend Q_CORE_EXPORT size_t qHash(const QRegExp &key, size_t seed) noexcept;
diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp
index 72ea8015ae..6ff42129b3 100644
--- a/src/corelib/text/qstring.cpp
+++ b/src/corelib/text/qstring.cpp
@@ -3918,138 +3918,7 @@ Q_DECLARE_TYPEINFO(QStringCapture, Q_PRIMITIVE_TYPE);
*/
QString& QString::replace(const QRegExp &rx, const QString &after)
{
- QRegExp rx2(rx);
-
- if (isEmpty() && rx2.indexIn(*this) == -1)
- return *this;
-
- reallocData(uint(d.size) + 1u);
-
- int index = 0;
- int numCaptures = rx2.captureCount();
- int al = after.length();
- QRegExp::CaretMode caretMode = QRegExp::CaretAtZero;
-
- if (numCaptures > 0) {
- const QChar *uc = after.unicode();
- int numBackRefs = 0;
-
- for (int i = 0; i < al - 1; i++) {
- if (uc[i] == QLatin1Char('\\')) {
- int no = uc[i + 1].digitValue();
- if (no > 0 && no <= numCaptures)
- numBackRefs++;
- }
- }
-
- /*
- This is the harder case where we have back-references.
- */
- if (numBackRefs > 0) {
- QVarLengthArray<QStringCapture, 16> captures(numBackRefs);
- int j = 0;
-
- for (int i = 0; i < al - 1; i++) {
- if (uc[i] == QLatin1Char('\\')) {
- int no = uc[i + 1].digitValue();
- if (no > 0 && no <= numCaptures) {
- QStringCapture capture;
- capture.pos = i;
- capture.len = 2;
-
- if (i < al - 2) {
- int secondDigit = uc[i + 2].digitValue();
- if (secondDigit != -1 && ((no * 10) + secondDigit) <= numCaptures) {
- no = (no * 10) + secondDigit;
- ++capture.len;
- }
- }
-
- capture.no = no;
- captures[j++] = capture;
- }
- }
- }
-
- while (index <= length()) {
- index = rx2.indexIn(*this, index, caretMode);
- if (index == -1)
- break;
-
- QString after2(after);
- for (j = numBackRefs - 1; j >= 0; j--) {
- const QStringCapture &capture = captures[j];
- after2.replace(capture.pos, capture.len, rx2.cap(capture.no));
- }
-
- replace(index, rx2.matchedLength(), after2);
- index += after2.length();
-
- // avoid infinite loop on 0-length matches (e.g., QRegExp("[a-z]*"))
- if (rx2.matchedLength() == 0)
- ++index;
-
- caretMode = QRegExp::CaretWontMatch;
- }
- return *this;
- }
- }
-
- /*
- This is the simple and optimized case where we don't have
- back-references.
- */
- while (index != -1) {
- struct {
- int pos;
- int length;
- } replacements[2048];
-
- int pos = 0;
- int adjust = 0;
- while (pos < 2047) {
- index = rx2.indexIn(*this, index, caretMode);
- if (index == -1)
- break;
- int ml = rx2.matchedLength();
- replacements[pos].pos = index;
- replacements[pos++].length = ml;
- index += ml;
- adjust += al - ml;
- // avoid infinite loop
- if (!ml)
- index++;
- }
- if (!pos)
- break;
- replacements[pos].pos = d.size;
- int newlen = d.size + adjust;
-
- // to continue searching at the right position after we did
- // the first round of replacements
- if (index != -1)
- index += adjust;
- QString newstring;
- newstring.reserve(newlen + 1);
- QChar *newuc = newstring.data();
- QChar *uc = newuc;
- int copystart = 0;
- int i = 0;
- while (i < pos) {
- int copyend = replacements[i].pos;
- int size = copyend - copystart;
- memcpy(static_cast<void*>(uc), static_cast<const void *>(d.data() + copystart), size * sizeof(QChar));
- uc += size;
- memcpy(static_cast<void *>(uc), static_cast<const void *>(after.d.data()), al * sizeof(QChar));
- uc += al;
- copystart = copyend + replacements[i].length;
- i++;
- }
- memcpy(static_cast<void *>(uc), static_cast<const void *>(d.data() + copystart), (d.size - copystart) * sizeof(QChar));
- newstring.resize(newlen);
- *this = newstring;
- caretMode = QRegExp::CaretWontMatch;
- }
+ *this = rx.replaceIn(*this, after);
return *this;
}
#endif
@@ -4402,17 +4271,7 @@ int QString::lastIndexOf(QRegExp& rx, int from) const
*/
int QString::count(const QRegExp& rx) const
{
- QRegExp rx2(rx);
- int count = 0;
- int index = -1;
- int len = length();
- while (index < len - 1) { // count overlapping matches
- index = rx2.indexIn(*this, index + 1);
- if (index == -1)
- break;
- count++;
- }
- return count;
+ return rx.countIn(*this);
}
#endif // QT_NO_REGEXP
@@ -4756,25 +4615,7 @@ static QString extractSections(const QVector<qt_section_chunk> &sections,
*/
QString QString::section(const QRegExp &reg, int start, int end, SectionFlags flags) const
{
- const QChar *uc = unicode();
- if(!uc)
- return QString();
-
- QRegExp sep(reg);
- sep.setCaseSensitivity((flags & SectionCaseInsensitiveSeps) ? Qt::CaseInsensitive
- : Qt::CaseSensitive);
-
- QVector<qt_section_chunk> sections;
- int n = length(), m = 0, last_m = 0, last_len = 0;
- while ((m = sep.indexIn(*this, m)) != -1) {
- sections.append(qt_section_chunk(last_len, QStringRef(this, last_m, m - last_m)));
- last_m = m;
- last_len = sep.matchedLength();
- m += qMax(sep.matchedLength(), 1);
- }
- sections.append(qt_section_chunk(last_len, QStringRef(this, last_m, n - last_m)));
-
- return extractSections(sections, start, end, flags);
+ return reg.sectionIn(*this, start, end, flags);
}
#endif
@@ -7742,28 +7583,6 @@ QVector<QStringRef> QStringRef::split(QChar sep, QString::SplitBehavior behavior
#endif
#ifndef QT_NO_REGEXP
-namespace {
-template<class ResultList, typename MidMethod>
-static ResultList splitString(const QString &source, MidMethod mid, const QRegExp &rx, Qt::SplitBehavior behavior)
-{
- QRegExp rx2(rx);
- ResultList list;
- int start = 0;
- int extra = 0;
- int end;
- while ((end = rx2.indexIn(source, start + extra)) != -1) {
- int matchedLen = rx2.matchedLength();
- if (start != end || behavior == Qt::KeepEmptyParts)
- list.append((source.*mid)(start, end - start));
- start = end + matchedLen;
- extra = (matchedLen == 0) ? 1 : 0;
- }
- if (start != source.size() || behavior == Qt::KeepEmptyParts)
- list.append((source.*mid)(start, -1));
- return list;
-}
-} // namespace
-
/*!
\overload
\since 5.14
@@ -7793,7 +7612,7 @@ static ResultList splitString(const QString &source, MidMethod mid, const QRegEx
*/
QStringList QString::split(const QRegExp &rx, Qt::SplitBehavior behavior) const
{
- return splitString<QStringList>(*this, &QString::mid, rx, behavior);
+ return rx.splitString(*this, behavior);
}
# if QT_DEPRECATED_SINCE(5, 15)
@@ -7803,7 +7622,7 @@ QStringList QString::split(const QRegExp &rx, Qt::SplitBehavior behavior) const
*/
QStringList QString::split(const QRegExp &rx, SplitBehavior behavior) const
{
- return split(rx, mapSplitBehavior(behavior));
+ return rx.splitString(*this, mapSplitBehavior(behavior));
}
# endif
@@ -7823,7 +7642,7 @@ QStringList QString::split(const QRegExp &rx, SplitBehavior behavior) const
*/
QVector<QStringRef> QString::splitRef(const QRegExp &rx, Qt::SplitBehavior behavior) const
{
- return splitString<QVector<QStringRef> >(*this, &QString::midRef, rx, behavior);
+ return rx.splitStringAsRef(*this, behavior);
}
# if QT_DEPRECATED_SINCE(5, 15)
@@ -7834,7 +7653,7 @@ QVector<QStringRef> QString::splitRef(const QRegExp &rx, Qt::SplitBehavior behav
*/
QVector<QStringRef> QString::splitRef(const QRegExp &rx, SplitBehavior behavior) const
{
- return splitRef(rx, mapSplitBehavior(behavior));
+ return rx.splitStringAsRef(*this, mapSplitBehavior(behavior));
}
# endif
#endif // QT_NO_REGEXP
diff --git a/src/corelib/text/qstringlist.cpp b/src/corelib/text/qstringlist.cpp
index 4b9dcee169..57abfb8f7d 100644
--- a/src/corelib/text/qstringlist.cpp
+++ b/src/corelib/text/qstringlist.cpp
@@ -460,11 +460,7 @@ bool QtPrivate::QStringList_contains(const QStringList *that, QLatin1String str,
*/
QStringList QtPrivate::QStringList_filter(const QStringList *that, const QRegExp &rx)
{
- QStringList res;
- for (int i = 0; i < that->size(); ++i)
- if (that->at(i).contains(rx))
- res << that->at(i);
- return res;
+ return rx.filterList(*that);
}
#endif
@@ -566,8 +562,7 @@ void QtPrivate::QStringList_replaceInStrings(QStringList *that, const QString &b
*/
void QtPrivate::QStringList_replaceInStrings(QStringList *that, const QRegExp &rx, const QString &after)
{
- for (int i = 0; i < that->size(); ++i)
- (*that)[i].replace(rx, after);
+ *that = rx.replaceIn(*that, after);
}
#endif
@@ -716,30 +711,6 @@ QString QtPrivate::QStringList_join(const QStringList *that, QStringView sep)
*/
#ifndef QT_NO_REGEXP
-static int indexOfMutating(const QStringList *that, QRegExp &rx, int from)
-{
- if (from < 0)
- from = qMax(from + that->size(), 0);
- for (int i = from; i < that->size(); ++i) {
- if (rx.exactMatch(that->at(i)))
- return i;
- }
- return -1;
-}
-
-static int lastIndexOfMutating(const QStringList *that, QRegExp &rx, int from)
-{
- if (from < 0)
- from += that->size();
- else if (from >= that->size())
- from = that->size() - 1;
- for (int i = from; i >= 0; --i) {
- if (rx.exactMatch(that->at(i)))
- return i;
- }
- return -1;
-}
-
/*!
\fn int QStringList::indexOf(const QRegExp &rx, int from) const
@@ -752,7 +723,7 @@ static int lastIndexOfMutating(const QStringList *that, QRegExp &rx, int from)
int QtPrivate::QStringList_indexOf(const QStringList *that, const QRegExp &rx, int from)
{
QRegExp rx2(rx);
- return indexOfMutating(that, rx2, from);
+ return rx2.indexIn(*that, from);
}
/*!
@@ -771,7 +742,7 @@ int QtPrivate::QStringList_indexOf(const QStringList *that, const QRegExp &rx, i
*/
int QtPrivate::QStringList_indexOf(const QStringList *that, QRegExp &rx, int from)
{
- return indexOfMutating(that, rx, from);
+ return rx.indexIn(*that, from);
}
/*!
@@ -787,7 +758,7 @@ int QtPrivate::QStringList_indexOf(const QStringList *that, QRegExp &rx, int fro
int QtPrivate::QStringList_lastIndexOf(const QStringList *that, const QRegExp &rx, int from)
{
QRegExp rx2(rx);
- return lastIndexOfMutating(that, rx2, from);
+ return rx2.lastIndexIn(*that, from);
}
/*!
@@ -807,7 +778,7 @@ int QtPrivate::QStringList_lastIndexOf(const QStringList *that, const QRegExp &r
*/
int QtPrivate::QStringList_lastIndexOf(const QStringList *that, QRegExp &rx, int from)
{
- return lastIndexOfMutating(that, rx, from);
+ return rx.lastIndexIn(*that, from);
}
#endif
diff --git a/tests/auto/corelib/text/qregexp/tst_qregexp.cpp b/tests/auto/corelib/text/qregexp/tst_qregexp.cpp
index a8111af6c1..d1dad01abb 100644
--- a/tests/auto/corelib/text/qregexp/tst_qregexp.cpp
+++ b/tests/auto/corelib/text/qregexp/tst_qregexp.cpp
@@ -69,6 +69,20 @@ private slots:
void validityCheck_data();
void validityCheck();
void escapeSequences();
+
+ void splitString_data();
+ void splitString();
+
+ void countIn();
+ void containedIn();
+
+ void replaceIn_data();
+ void replaceIn();
+ void removeIn_data();
+ void removeIn();
+
+ void filterList();
+ void replaceInList();
};
// Testing get/set functions
@@ -1381,6 +1395,155 @@ void tst_QRegExp::escapeSequences()
}
}
+void tst_QRegExp::splitString_data()
+{
+ QTest::addColumn<QString>("string");
+ QTest::addColumn<QString>("pattern");
+ QTest::addColumn<QStringList>("result");
+
+ QTest::newRow("data01") << "Some text\n\twith strange whitespace."
+ << "\\s+"
+ << (QStringList() << "Some" << "text" << "with" << "strange" << "whitespace." );
+
+ QTest::newRow("data02") << "This time, a normal English sentence."
+ << "\\W+"
+ << (QStringList() << "This" << "time" << "a" << "normal" << "English" << "sentence" << "");
+
+ QTest::newRow("data03") << "Now: this sentence fragment."
+ << "\\b"
+ << (QStringList() << "" << "Now" << ": " << "this" << " " << "sentence" << " " << "fragment" << ".");
+}
+
+void tst_QRegExp::splitString()
+{
+ QFETCH(QString, string);
+ QFETCH(QString, pattern);
+ QFETCH(QStringList, result);
+ QStringList list = QRegExp(pattern).splitString(string);
+ QVERIFY(list == result);
+
+ QVERIFY(list == result);
+
+ result.removeAll(QString());
+
+ list = QRegExp(pattern).splitString(string, Qt::SkipEmptyParts);
+ QVERIFY(list == result);
+}
+
+void tst_QRegExp::countIn()
+{
+ QString a;
+ a="ABCDEFGHIEfGEFG"; // 15 chars
+ QCOMPARE(QRegExp("[FG][HI]").countIn(a),1);
+ QCOMPARE(QRegExp("[G][HE]").countIn(a),2);
+}
+
+
+void tst_QRegExp::containedIn()
+{
+ QString a;
+ a="ABCDEFGHIEfGEFG"; // 15 chars
+ QVERIFY(QRegExp("[FG][HI]").containedIn(a));
+ QVERIFY(QRegExp("[G][HE]").containedIn(a));
+}
+
+void tst_QRegExp::replaceIn_data()
+{
+ QTest::addColumn<QString>("string" );
+ QTest::addColumn<QString>("regexp" );
+ QTest::addColumn<QString>("after" );
+ QTest::addColumn<QString>("result" );
+
+ QTest::newRow( "rem00" ) << QString("alpha") << QString("a+") << QString("") << QString("lph");
+ QTest::newRow( "rem01" ) << QString("banana") << QString("^.a") << QString("") << QString("nana");
+ QTest::newRow( "rem02" ) << QString("") << QString("^.a") << QString("") << QString("");
+ QTest::newRow( "rem03" ) << QString("") << QString("^.a") << QString() << QString("");
+ QTest::newRow( "rem04" ) << QString() << QString("^.a") << QString("") << QString();
+ QTest::newRow( "rem05" ) << QString() << QString("^.a") << QString() << QString();
+
+ QTest::newRow( "rep00" ) << QString("A <i>bon mot</i>.") << QString("<i>([^<]*)</i>") << QString("\\emph{\\1}") << QString("A \\emph{bon mot}.");
+ QTest::newRow( "rep01" ) << QString("banana") << QString("^.a()") << QString("\\1") << QString("nana");
+ QTest::newRow( "rep02" ) << QString("banana") << QString("(ba)") << QString("\\1X\\1") << QString("baXbanana");
+ QTest::newRow( "rep03" ) << QString("banana") << QString("(ba)(na)na") << QString("\\2X\\1") << QString("naXba");
+
+ QTest::newRow("backref00") << QString("\\1\\2\\3\\4\\5\\6\\7\\8\\9\\A\\10\\11") << QString("\\\\[34]")
+ << QString("X") << QString("\\1\\2XX\\5\\6\\7\\8\\9\\A\\10\\11");
+ QTest::newRow("backref01") << QString("foo") << QString("[fo]") << QString("\\1") << QString("\\1\\1\\1");
+ QTest::newRow("backref02") << QString("foo") << QString("([fo])") << QString("(\\1)") << QString("(f)(o)(o)");
+ QTest::newRow("backref03") << QString("foo") << QString("([fo])") << QString("\\2") << QString("\\2\\2\\2");
+ QTest::newRow("backref04") << QString("foo") << QString("([fo])") << QString("\\10") << QString("f0o0o0");
+ QTest::newRow("backref05") << QString("foo") << QString("([fo])") << QString("\\11") << QString("f1o1o1");
+ QTest::newRow("backref06") << QString("foo") << QString("([fo])") << QString("\\19") << QString("f9o9o9");
+ QTest::newRow("backref07") << QString("foo") << QString("(f)(o+)")
+ << QString("\\2\\1\\10\\20\\11\\22\\19\\29\\3")
+ << QString("ooff0oo0f1oo2f9oo9\\3");
+ QTest::newRow("backref08") << QString("abc") << QString("(((((((((((((([abc]))))))))))))))")
+ << QString("{\\14}") << QString("{a}{b}{c}");
+ QTest::newRow("backref09") << QString("abcdefghijklmn")
+ << QString("(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)(m)(n)")
+ << QString("\\19\\18\\17\\16\\15\\14\\13\\12\\11\\10"
+ "\\9\\90\\8\\80\\7\\70\\6\\60\\5\\50\\4\\40\\3\\30\\2\\20\\1")
+ << QString("a9a8a7a6a5nmlkjii0hh0gg0ff0ee0dd0cc0bb0a");
+ QTest::newRow("backref10") << QString("abc") << QString("((((((((((((((abc))))))))))))))")
+ << QString("\\0\\01\\011") << QString("\\0\\01\\011");
+ QTest::newRow("invalid") << QString("") << QString("invalid regex\\") << QString("") << QString("");
+}
+
+void tst_QRegExp::replaceIn()
+{
+ QFETCH( QString, string );
+ QFETCH( QString, regexp );
+ QFETCH( QString, after );
+
+ QString s2 = string;
+ s2 = QRegExp(regexp).replaceIn(s2, after);
+ QTEST( s2, "result" );
+ s2 = string;
+}
+
+void tst_QRegExp::removeIn_data()
+{
+ replaceIn_data();
+}
+
+void tst_QRegExp::removeIn()
+{
+ QFETCH( QString, string );
+ QFETCH( QString, regexp );
+ QFETCH( QString, after );
+
+ if ( after.length() == 0 ) {
+ QString s2 = string;
+ s2 = QRegExp(regexp).removeIn(s2);
+ QTEST( s2, "result" );
+ } else {
+ QCOMPARE( 0, 0 ); // shut Qt Test
+ }
+}
+
+void tst_QRegExp::filterList()
+{
+ QStringList list3, list4;
+ list3 << "Bill Gates" << "Joe Blow" << "Bill Clinton";
+ list3 = QRegExp("[i]ll") .filterList(list3);
+ list4 << "Bill Gates" << "Bill Clinton";
+ QCOMPARE( list3, list4 );
+}
+
+void tst_QRegExp::replaceInList()
+{
+ QStringList list3, list4;
+ list3 << "alpha" << "beta" << "gamma" << "epsilon";
+ list3 = QRegExp("^a").replaceIn(list3, "o");
+ list4 << "olpha" << "beta" << "gamma" << "epsilon";
+ QCOMPARE( list3, list4 );
+
+ QStringList list5, list6;
+ list5 << "Bill Clinton" << "Gates, Bill";
+ list6 << "Bill Clinton" << "Bill Gates";
+ list5 = QRegExp("^(.*), (.*)$").replaceIn(list5, "\\2 \\1");
+ QCOMPARE( list5, list6 );
+}
QTEST_APPLESS_MAIN(tst_QRegExp)
#include "tst_qregexp.moc"