summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/global/qnamespace.h8
-rw-r--r--src/corelib/global/qnamespace.qdoc13
-rw-r--r--src/corelib/tools/qstring.h29
-rw-r--r--src/corelib/tools/qstringlist.h17
-rw-r--r--src/corelib/tools/qvector.h18
-rw-r--r--tests/auto/corelib/tools/qstringapisymmetry/tst_qstringapisymmetry.cpp141
6 files changed, 226 insertions, 0 deletions
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h
index 5e94b75127..8b27c60fec 100644
--- a/src/corelib/global/qnamespace.h
+++ b/src/corelib/global/qnamespace.h
@@ -194,6 +194,13 @@ public:
DescendingOrder
};
+ enum SplitBehaviorFlags {
+ KeepEmptyParts = 0,
+ SkipEmptyParts = 0x1,
+ };
+ Q_DECLARE_FLAGS(SplitBehavior, SplitBehaviorFlags)
+ Q_DECLARE_OPERATORS_FOR_FLAGS(SplitBehavior)
+
enum TileRule {
StretchTile,
RepeatTile,
@@ -1772,6 +1779,7 @@ public:
QT_Q_FLAG(Alignment)
QT_Q_ENUM(TextFlag)
QT_Q_FLAG(Orientations)
+ QT_Q_FLAG(SplitBehavior)
QT_Q_FLAG(DropActions)
QT_Q_FLAG(Edges)
QT_Q_FLAG(DockWidgetAreas)
diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc
index 5bba8c5fe5..290b060399 100644
--- a/src/corelib/global/qnamespace.qdoc
+++ b/src/corelib/global/qnamespace.qdoc
@@ -2362,6 +2362,19 @@
*/
/*!
+ \enum Qt::SplitBehavior
+ \since 5.14
+
+ This enum specifies how the split() functions should behave with
+ respect to empty strings.
+
+ \value KeepEmptyParts If a field is empty, keep it in the result.
+ \value SkipEmptyParts If a field is empty, don't include it in the result.
+
+ \sa QString::split()
+*/
+
+/*!
\enum Qt::ClipOperation
\value NoClip This operation turns clipping off.
diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h
index 1feb8e186c..5bc3a87832 100644
--- a/src/corelib/tools/qstring.h
+++ b/src/corelib/tools/qstring.h
@@ -545,6 +545,30 @@ public:
Q_REQUIRED_RESULT QStringList split(const QRegularExpression &sep, SplitBehavior behavior = KeepEmptyParts) const;
Q_REQUIRED_RESULT QVector<QStringRef> splitRef(const QRegularExpression &sep, SplitBehavior behavior = KeepEmptyParts) const;
#endif
+
+private:
+ static Q_DECL_CONSTEXPR SplitBehavior _sb(Qt::SplitBehavior sb) Q_DECL_NOTHROW
+ { return sb & Qt::SkipEmptyParts ? SkipEmptyParts : KeepEmptyParts; }
+public:
+
+ Q_REQUIRED_RESULT inline QStringList split(const QString &sep, Qt::SplitBehavior behavior,
+ Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
+ Q_REQUIRED_RESULT inline QVector<QStringRef> splitRef(const QString &sep, Qt::SplitBehavior behavior,
+ Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
+ Q_REQUIRED_RESULT inline QStringList split(QChar sep, Qt::SplitBehavior behavior,
+ Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
+ Q_REQUIRED_RESULT inline QVector<QStringRef> splitRef(QChar sep, Qt::SplitBehavior behavior,
+ Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
+#ifndef QT_NO_REGEXP
+ Q_REQUIRED_RESULT inline QStringList split(const QRegExp &sep, Qt::SplitBehavior behavior) const;
+ Q_REQUIRED_RESULT inline QVector<QStringRef> splitRef(const QRegExp &sep, Qt::SplitBehavior behavior) const;
+#endif
+#ifndef QT_NO_REGULAREXPRESSION
+ Q_REQUIRED_RESULT inline QStringList split(const QRegularExpression &sep, Qt::SplitBehavior behavior) const;
+ Q_REQUIRED_RESULT inline QVector<QStringRef> splitRef(const QRegularExpression &sep, Qt::SplitBehavior behavior) const;
+#endif
+
+
enum NormalizationForm {
NormalizationForm_D,
NormalizationForm_C,
@@ -1514,6 +1538,11 @@ public:
Q_REQUIRED_RESULT QVector<QStringRef> split(QChar sep, QString::SplitBehavior behavior = QString::KeepEmptyParts,
Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
+ Q_REQUIRED_RESULT inline QVector<QStringRef> split(const QString &sep, Qt::SplitBehavior behavior,
+ Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
+ Q_REQUIRED_RESULT inline QVector<QStringRef> split(QChar sep, Qt::SplitBehavior behavior,
+ Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
+
Q_REQUIRED_RESULT QStringRef left(int n) const;
Q_REQUIRED_RESULT QStringRef right(int n) const;
Q_REQUIRED_RESULT QStringRef mid(int pos, int n = -1) const;
diff --git a/src/corelib/tools/qstringlist.h b/src/corelib/tools/qstringlist.h
index 81748e9a0b..3bb657069b 100644
--- a/src/corelib/tools/qstringlist.h
+++ b/src/corelib/tools/qstringlist.h
@@ -330,6 +330,23 @@ inline int QStringList::lastIndexOf(const QRegularExpression &rx, int from) cons
#endif // QT_CONFIG(regularexpression)
#endif // Q_QDOC
+//
+// QString inline functions:
+//
+
+QStringList QString::split(const QString &sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
+{ return split(sep, _sb(behavior), cs); }
+QStringList QString::split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
+{ return split(sep, _sb(behavior), cs); }
+#ifndef QT_NO_REGEXP
+QStringList QString::split(const QRegExp &sep, Qt::SplitBehavior behavior) const
+{ return split(sep, _sb(behavior)); }
+#endif
+#if QT_CONFIG(regularexpression)
+QStringList QString::split(const QRegularExpression &sep, Qt::SplitBehavior behavior) const
+{ return split(sep, _sb(behavior)); }
+#endif
+
QT_END_NAMESPACE
#endif // QSTRINGLIST_H
diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h
index 492afeac75..c223e4efa0 100644
--- a/src/corelib/tools/qvector.h
+++ b/src/corelib/tools/qvector.h
@@ -1125,6 +1125,24 @@ extern template class Q_CORE_EXPORT QVector<QPoint>;
QVector<uint> QStringView::toUcs4() const { return QtPrivate::convertToUcs4(*this); }
+QVector<QStringRef> QString::splitRef(const QString &sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
+{ return splitRef(sep, _sb(behavior), cs); }
+QVector<QStringRef> QString::splitRef(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
+{ return splitRef(sep, _sb(behavior), cs); }
+#ifndef QT_NO_REGEXP
+QVector<QStringRef> QString::splitRef(const QRegExp &sep, Qt::SplitBehavior behavior) const
+{ return splitRef(sep, _sb(behavior)); }
+#endif
+#if QT_CONFIG(regularexpression)
+QVector<QStringRef> QString::splitRef(const QRegularExpression &sep, Qt::SplitBehavior behavior) const
+{ return splitRef(sep, _sb(behavior)); }
+#endif
+QVector<QStringRef> QStringRef::split(const QString &sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
+{ return split(sep, QString::_sb(behavior), cs); }
+QVector<QStringRef> QStringRef::split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
+{ return split(sep, QString::_sb(behavior), cs); }
+
+
QT_END_NAMESPACE
#endif // QVECTOR_H
diff --git a/tests/auto/corelib/tools/qstringapisymmetry/tst_qstringapisymmetry.cpp b/tests/auto/corelib/tools/qstringapisymmetry/tst_qstringapisymmetry.cpp
index b52c15fd73..3062c09db3 100644
--- a/tests/auto/corelib/tools/qstringapisymmetry/tst_qstringapisymmetry.cpp
+++ b/tests/auto/corelib/tools/qstringapisymmetry/tst_qstringapisymmetry.cpp
@@ -48,6 +48,14 @@ QString toQString(const T &t) { return QString(t); }
QString toQString(const QStringRef &ref) { return ref.toString(); }
QString toQString(QStringView view) { return view.toString(); }
+template <typename Iterable>
+QStringList toQStringList(const Iterable &i) {
+ QStringList result;
+ for (auto &e : i)
+ result.push_back(toQString(e));
+ return result;
+}
+
// FIXME: these are missing at the time of writing, add them, then remove the dummies here:
#define MAKE_RELOP(op, A1, A2) \
static bool operator op (A1 lhs, A2 rhs) \
@@ -293,6 +301,26 @@ private Q_SLOTS:
void endsWith_QLatin1String_QChar() { endsWith_impl<QLatin1String, QChar>(); }
private:
+ void split_data(bool rhsHasVariableLength = true);
+ template <typename Haystack, typename Needle> void split_impl() const;
+
+private Q_SLOTS:
+ // test all combinations of {QString, QStringRef} x {QString, QLatin1String, QChar}:
+ void split_QString_QString_data() { split_data(); }
+ void split_QString_QString() { split_impl<QString, QString>(); }
+ void split_QString_QLatin1String_data() { split_data(); }
+ void split_QString_QLatin1String() { split_impl<QString, QLatin1String>(); }
+ void split_QString_QChar_data() { split_data(false); }
+ void split_QString_QChar() { split_impl<QString, QChar>(); }
+
+ void split_QStringRef_QString_data() { split_data(); }
+ void split_QStringRef_QString() { split_impl<QStringRef, QString>(); }
+ void split_QStringRef_QLatin1String_data() { split_data(); }
+ void split_QStringRef_QLatin1String() { split_impl<QStringRef, QLatin1String>(); }
+ void split_QStringRef_QChar_data() { split_data(false); }
+ void split_QStringRef_QChar() { split_impl<QStringRef, QChar>(); }
+
+private:
void mid_data();
template <typename String> void mid_impl();
@@ -780,6 +808,119 @@ void tst_QStringApiSymmetry::endsWith_impl() const
QCOMPARE(haystack.endsWith(needle, Qt::CaseInsensitive), resultCIS);
}
+void tst_QStringApiSymmetry::split_data(bool rhsHasVariableLength)
+{
+ QTest::addColumn<QStringRef>("haystackU16");
+ QTest::addColumn<QLatin1String>("haystackL1");
+ QTest::addColumn<QStringRef>("needleU16");
+ QTest::addColumn<QLatin1String>("needleL1");
+ QTest::addColumn<QStringList>("resultCS");
+ QTest::addColumn<QStringList>("resultCIS");
+
+ if (rhsHasVariableLength) {
+ QTest::addRow("null ~= null$") << QStringRef{} << QLatin1String{}
+ << QStringRef{} << QLatin1String{}
+ << QStringList{{}, {}} << QStringList{{}, {}};
+ QTest::addRow("empty ~= null$") << QStringRef{&empty} << QLatin1String("")
+ << QStringRef{} << QLatin1String{}
+ << QStringList{empty, empty} << QStringList{empty, empty};
+ QTest::addRow("a ~= null$") << QStringRef{&a} << QLatin1String{"a"}
+ << QStringRef{} << QLatin1String{}
+ << QStringList{empty, a, empty} << QStringList{empty, a, empty};
+ QTest::addRow("null ~= empty$") << QStringRef{} << QLatin1String{}
+ << QStringRef{&empty} << QLatin1String{""}
+ << QStringList{{}, {}} << QStringList{{}, {}};
+ QTest::addRow("a ~= empty$") << QStringRef{&a} << QLatin1String{"a"}
+ << QStringRef{&empty} << QLatin1String{""}
+ << QStringList{empty, a, empty} << QStringList{empty, a, empty};
+ QTest::addRow("empty ~= empty$") << QStringRef{&empty} << QLatin1String{""}
+ << QStringRef{&empty} << QLatin1String{""}
+ << QStringList{empty, empty} << QStringList{empty, empty};
+ }
+ QTest::addRow("null ~= a$") << QStringRef{} << QLatin1String{}
+ << QStringRef{&a} << QLatin1String{"a"}
+ << QStringList{{}} << QStringList{{}};
+ QTest::addRow("empty ~= a$") << QStringRef{&empty} << QLatin1String{""}
+ << QStringRef{&a} << QLatin1String{"a"}
+ << QStringList{empty} << QStringList{empty};
+
+#define ROW(h, n, cs, cis) \
+ QTest::addRow("%s ~= %s$", #h, #n) << QStringRef(&h) << QLatin1String(#h) \
+ << QStringRef(&n) << QLatin1String(#n) \
+ << QStringList cs << QStringList cis
+ ROW(a, a, ({empty, empty}), ({empty, empty}));
+ ROW(a, A, {a}, ({empty, empty}));
+ ROW(a, b, {a}, {a});
+
+ if (rhsHasVariableLength)
+ ROW(b, ab, {b}, {b});
+
+ ROW(ab, b, ({a, empty}), ({a, empty}));
+ if (rhsHasVariableLength) {
+ ROW(ab, ab, ({empty, empty}), ({empty, empty}));
+ ROW(ab, aB, {ab}, ({empty, empty}));
+ ROW(ab, Ab, {ab}, ({empty, empty}));
+ }
+ ROW(ab, c, {ab}, {ab});
+
+ if (rhsHasVariableLength)
+ ROW(bc, abc, {bc}, {bc});
+
+ ROW(Abc, c, ({Ab, empty}), ({Ab, empty}));
+#if 0
+ if (rhsHasVariableLength) {
+ ROW(Abc, bc, 1, 1);
+ ROW(Abc, bC, 0, 1);
+ ROW(Abc, Bc, 0, 1);
+ ROW(Abc, BC, 0, 1);
+ ROW(aBC, bc, 0, 1);
+ ROW(aBC, bC, 0, 1);
+ ROW(aBC, Bc, 0, 1);
+ ROW(aBC, BC, 1, 1);
+ }
+#endif
+ ROW(ABC, b, {ABC}, ({A, C}));
+ ROW(ABC, a, {ABC}, ({empty, BC}));
+#undef ROW
+}
+
+static QStringList skipped(const QStringList &sl)
+{
+ QStringList result;
+ result.reserve(sl.size());
+ for (const QString &s : sl) {
+ if (!s.isEmpty())
+ result.push_back(s);
+ }
+ return result;
+}
+
+template <typename Haystack, typename Needle>
+void tst_QStringApiSymmetry::split_impl() const
+{
+ QFETCH(const QStringRef, haystackU16);
+ QFETCH(const QLatin1String, haystackL1);
+ QFETCH(const QStringRef, needleU16);
+ QFETCH(const QLatin1String, needleL1);
+ QFETCH(const QStringList, resultCS);
+ QFETCH(const QStringList, resultCIS);
+
+ const QStringList skippedResultCS = skipped(resultCS);
+ const QStringList skippedResultCIS = skipped(resultCIS);
+
+ const auto haystackU8 = haystackU16.toUtf8();
+ const auto needleU8 = needleU16.toUtf8();
+
+ const auto haystack = make<Haystack>(haystackU16, haystackL1, haystackU8);
+ const auto needle = make<Needle>(needleU16, needleL1, needleU8);
+
+ QCOMPARE(toQStringList(haystack.split(needle)), resultCS);
+ QCOMPARE(toQStringList(haystack.split(needle, Qt::KeepEmptyParts, Qt::CaseSensitive)), resultCS);
+ QCOMPARE(toQStringList(haystack.split(needle, Qt::KeepEmptyParts, Qt::CaseInsensitive)), resultCIS);
+ QCOMPARE(toQStringList(haystack.split(needle, Qt::SkipEmptyParts, Qt::CaseSensitive)), skippedResultCS);
+ QCOMPARE(toQStringList(haystack.split(needle, Qt::SkipEmptyParts, Qt::CaseInsensitive)), skippedResultCIS);
+}
+
void tst_QStringApiSymmetry::mid_data()
{
QTest::addColumn<QStringRef>("unicode");