From aac39167b7903eea886d8638ab84296d4e8952f1 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 22 May 2020 16:47:19 +0200 Subject: Add QStringView::split() methods Since QString::split() is not going away in Qt 6, we should aim to provide API symmetry here, and ease porting existing code from QString(Ref) to use QStringView. This is easier than having to port everything to use tokenize() at the same time. tokenize() will however lead to better performance and thus should be preferred. Change-Id: I1eb43300a90167c6e9389ab56f416f2bf7edf506 Reviewed-by: Volker Hilsheimer --- src/corelib/text/qstring.cpp | 59 ++++++++++++++++++++++--- src/corelib/text/qstringview.h | 16 +++++++ tests/auto/corelib/text/qstring/tst_qstring.cpp | 50 +++++++++++++++------ 3 files changed, 105 insertions(+), 20 deletions(-) diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index 01b4337c2a..e026829a3d 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -7197,7 +7197,7 @@ static ResultList splitString(const StringSource &source, QStringView sep, extra = (sep.size() == 0 ? 1 : 0); } if (start != source.size() || behavior == Qt::KeepEmptyParts) - list.append(source.mid(start, -1)); + list.append(source.mid(start)); return list; } @@ -7381,10 +7381,37 @@ QVector QStringRef::split(QChar sep, QString::SplitBehavior behavior } #endif + +/*! + \fn QList QStringView::split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const + \fn QList QStringView::split(QStringView sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const + + + Splits the string into substring references wherever \a sep occurs, and + returns the list of those strings. + + See QString::split() for how \a sep, \a behavior and \a cs interact to form + the result. + + \note All references are valid as long this string is alive. Destroying this + string will cause all references to be dangling pointers. + + \since 6.0 +*/ +QList QStringView::split(QStringView sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const +{ + return splitString>(QStringView(*this), sep, behavior, cs); +} + +QList QStringView::split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const +{ + return split(QStringView(&sep, 1), behavior, cs); +} + #if QT_CONFIG(regularexpression) namespace { -template -static ResultList splitString(const QString &source, MidMethod mid, const QRegularExpression &re, +template +static ResultList splitString(const String &source, const QRegularExpression &re, Qt::SplitBehavior behavior) { ResultList list; @@ -7400,12 +7427,12 @@ static ResultList splitString(const QString &source, MidMethod mid, const QRegul QRegularExpressionMatch match = iterator.next(); end = match.capturedStart(); if (start != end || behavior == Qt::KeepEmptyParts) - list.append((source.*mid)(start, end - start)); + list.append(source.mid(start, end - start)); start = match.capturedEnd(); } if (start != source.size() || behavior == Qt::KeepEmptyParts) - list.append((source.*mid)(start, -1)); + list.append(source.mid(start)); return list; } @@ -7440,7 +7467,7 @@ static ResultList splitString(const QString &source, MidMethod mid, const QRegul */ QStringList QString::split(const QRegularExpression &re, Qt::SplitBehavior behavior) const { - return splitString(*this, &QString::mid, re, behavior); + return splitString(*this, re, behavior); } # if QT_DEPRECATED_SINCE(5, 15) @@ -7471,7 +7498,25 @@ QStringList QString::split(const QRegularExpression &re, SplitBehavior behavior) */ QVector QString::splitRef(const QRegularExpression &re, Qt::SplitBehavior behavior) const { - return splitString >(*this, &QString::midRef, re, behavior); + return splitString >(QStringRef(this), re, behavior); +} + +/*! + \since 6.0 + + Splits the string into substring views wherever the regular expression + \a re matches, and returns the list of those strings. If \a re + does not match anywhere in the string, splitRef() returns a + single-element vector containing this string reference. + + \note All references are valid as long this string is alive. Destroying this + string will cause all references to be dangling pointers. + + \sa split() QStringRef +*/ +QList QStringView::split(const QRegularExpression &re, Qt::SplitBehavior behavior) const +{ + return splitString>(*this, re, behavior); } # if QT_DEPRECATED_SINCE(5, 15) diff --git a/src/corelib/text/qstringview.h b/src/corelib/text/qstringview.h index 5890515652..4e780628cc 100644 --- a/src/corelib/text/qstringview.h +++ b/src/corelib/text/qstringview.h @@ -73,6 +73,7 @@ QT_BEGIN_NAMESPACE class QString; class QStringRef; class QStringView; +class QRegularExpression; namespace QtPrivate { template @@ -339,6 +340,21 @@ public: Q_REQUIRED_RESULT inline int toWCharArray(wchar_t *array) const; // defined in qstring.h + + Q_REQUIRED_RESULT Q_CORE_EXPORT + QList split(QStringView sep, + Qt::SplitBehavior behavior = Qt::KeepEmptyParts, + Qt::CaseSensitivity cs = Qt::CaseSensitive) const; + Q_REQUIRED_RESULT Q_CORE_EXPORT + QList split(QChar sep, Qt::SplitBehavior behavior = Qt::KeepEmptyParts, + Qt::CaseSensitivity cs = Qt::CaseSensitive) const; + +#if QT_CONFIG(regularexpression) + Q_REQUIRED_RESULT Q_CORE_EXPORT + QList split(const QRegularExpression &sep, + Qt::SplitBehavior behavior = Qt::KeepEmptyParts) const; +#endif + // // STL compatibility API: // diff --git a/tests/auto/corelib/text/qstring/tst_qstring.cpp b/tests/auto/corelib/text/qstring/tst_qstring.cpp index ef93c732ac..0501a5765d 100644 --- a/tests/auto/corelib/text/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/text/qstring/tst_qstring.cpp @@ -5685,19 +5685,41 @@ template<> struct StringSplitWrapper { const QString &string; - QStringList split(const QString &sep, QString::SplitBehavior behavior = QString::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return string.split(sep, behavior, cs); } - QStringList split(QChar sep, QString::SplitBehavior behavior = QString::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return string.split(sep, behavior, cs); } - QStringList split(const QRegularExpression &sep, QString::SplitBehavior behavior = QString::KeepEmptyParts) const { return string.split(sep, behavior); } + QStringList split(const QString &sep, Qt::SplitBehavior behavior = Qt::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return string.split(sep, behavior, cs); } + QStringList split(QChar sep, Qt::SplitBehavior behavior = Qt::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return string.split(sep, behavior, cs); } + QStringList split(const QRegularExpression &sep, Qt::SplitBehavior behavior = Qt::KeepEmptyParts) const { return string.split(sep, behavior); } }; template<> struct StringSplitWrapper { const QString &string; - QVector split(const QString &sep, QString::SplitBehavior behavior = QString::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return string.splitRef(sep, behavior, cs); } - QVector split(QChar sep, QString::SplitBehavior behavior = QString::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return string.splitRef(sep, behavior, cs); } - QVector split(const QRegularExpression &sep, QString::SplitBehavior behavior = QString::KeepEmptyParts) const { return string.splitRef(sep, behavior); } + QVector split(const QString &sep, Qt::SplitBehavior behavior = Qt::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return string.splitRef(sep, behavior, cs); } + QVector split(QChar sep, Qt::SplitBehavior behavior = Qt::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return string.splitRef(sep, behavior, cs); } + QVector split(const QRegularExpression &sep, Qt::SplitBehavior behavior = Qt::KeepEmptyParts) const { return string.splitRef(sep, behavior); } }; +template<> struct StringSplitWrapper +{ + const QString &string; + QList split(const QString &sep, Qt::SplitBehavior behavior = Qt::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const + { return QStringView{string}.split(sep, behavior, cs); } + QList split(QChar sep, Qt::SplitBehavior behavior = Qt::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const + { return QStringView{string}.split(sep, behavior, cs); } + QList split(const QRegularExpression &sep, Qt::SplitBehavior behavior = Qt::KeepEmptyParts) const + { return QStringView{string}.split(sep, behavior); } +}; + +static bool operator==(const QList &result, const QStringList &expected) +{ + if (expected.size() != result.size()) + return false; + for (int i = 0; i < expected.size(); ++i) + if (expected.at(i) != result.at(i)) + return false; + return true; +} + + static bool operator ==(const QStringList &left, const QVector &right) { if (left.size() != right.size()) @@ -5732,22 +5754,22 @@ void tst_QString::split(const QString &string, const QString &sep, QStringList r QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED - list = str.split(sep, QString::KeepEmptyParts); + list = str.split(sep, Qt::KeepEmptyParts); QVERIFY(list == result); - list = str.split(re, QString::KeepEmptyParts); + list = str.split(re, Qt::KeepEmptyParts); QVERIFY(list == result); if (sep.size() == 1) { - list = str.split(sep.at(0), QString::KeepEmptyParts); + list = str.split(sep.at(0), Qt::KeepEmptyParts); QVERIFY(list == result); } result.removeAll(""); - list = str.split(sep, QString::SkipEmptyParts); + list = str.split(sep, Qt::SkipEmptyParts); QVERIFY(list == result); - list = str.split(re, QString::SkipEmptyParts); + list = str.split(re, Qt::SkipEmptyParts); QVERIFY(list == result); if (sep.size() == 1) { - list = str.split(sep.at(0), QString::SkipEmptyParts); + list = str.split(sep.at(0), Qt::SkipEmptyParts); QVERIFY(list == result); } QT_WARNING_POP @@ -5759,6 +5781,7 @@ void tst_QString::split() QFETCH(QString, sep); QFETCH(QStringList, result); split(str, sep, result); + split>(str, sep, result); } void tst_QString::splitRef_data() @@ -5804,7 +5827,7 @@ void tst_QString::split_regexp(const QString &_string, const QString &pattern, Q result.removeAll(QString()); - list = string.split(RegExp(pattern), QString::SkipEmptyParts); + list = string.split(RegExp(pattern), Qt::SkipEmptyParts); QVERIFY(list == result); } @@ -5814,6 +5837,7 @@ void tst_QString::split_regularexpression() QFETCH(QString, pattern); QFETCH(QStringList, result); split_regexp(string, pattern, result); + split_regexp, QRegularExpression>(string, pattern, result); } void tst_QString::splitRef_regularexpression_data() -- cgit v1.2.3