Some languages have ltrim(), rtrim() functions with arbitrary characters to trim, however seems QString in Qt does not have anything similar for now. How to implement such with current functionality? Regexp?
Note. Good if Qt team could add add ltrim(), rtrim() methods in QString() like some other languages have:
QString ltrim(QByteArray &chars); // trim left
QString rtrim(QByteArray &chars); // trim right
and overloaded
trimmed(QByteArray &chars)
to trim arbitrary characters, not only whitespaces. Should be very convenient.
If you believe the feature is important then you can post a feature request on https://bugreports.qt.io/. If you look at qstring.cpp you can see the function is fairly simple and you can create your own custom function much faster.
You can trim whitespaces, \n, \r etc with QString::simplified();
qDebug() << QString(" lots\t of\nwhitespace\r\n ").simplified();
Output: lots of whitespace
or if you like to trim custom letters, you can use QString::remove with QRegExp:
qDebug() << QString("13Hello").remove(QRegExp("^([0-9]{2})")); // trim 2 numbers at begin
Output: Hello
qDebug() << QString("Hello13").remove(QRegExp("([0-9]{2})$")); // trim 2 numbers at the end
Output: Hello
qDebug() << QString(",./Hello").remove(QRegExp("^([,|.|/]+)")); // trim matched characters at the begin
Output: Hello
qDebug() << QString("Hello,./").remove(QRegExp("([,|.|/]+)$")); // trim matched characters at the end
Output: Hello
A QByteArray is not a way to store QChars: QString is. Given that, the implementation is not complicated. The switch-over point between using ws.contains and std::binary_search should be selected based on a benchmark.
The trimmedRef, trimmedLeftRef and trimmedRightRef are optimizations that don't copy the source string. They can be used when the trimmed version of the string doesn't outlive the source string - this avoids a copy.
#include <QString>
#include <algorithm>
namespace detail { struct IsSpace final {
static QString sorted(QString s) {
std::sort(s.begin(), s.end());
return s;
}
QString const ws;
QString::const_iterator begin = ws.cBegin(), end = ws.cEnd();
bool (IsSpace::*test)(QChar) const =
ws.isEmpty() ? &IsSpace::test1 :
(ws.size() <= 8) ? &IsSpace::test2 :
&IsSpace::test3;
explicit IsSpace(const QString &whitespace) : ws(sorted(whitespace)) {}
bool test1(const QChar c) const { return c.isSpace(); }
bool test2(const QChar c) const { return ws.contains(c); }
bool test3(const QChar c) const { return std::binary_search(begin, end, c); }
inline bool operator()(QChar c) const { return (*this.*test)(c); }
}; }
enum TrimmedOption { TrimmedLeft = 1, TrimmedRight = 2 };
Q_DECLARE_FLAGS(TrimmedOptions, TrimmedOption)
Q_DECLARE_OPERATORS_FOR_FLAGS(TrimedOptions)
QStringRef trimmedRef(const QString &src, const QString &whitespace,
TrimmedOptions opt = TrimmedLeft | TrimmedRight) {
detail::IsSpace const isSpace{whitespace};
int l = 0;
if (options & TrimmedLeft)
while (l < src.length() && isSpace(src[l]))
l++;
int r = src.length();
if (options & TrimmedRight)
while (r > 0 && isSpace(src[r-1]))
r--;
return {&src, l, r-l};
}
QStringRef trimmedLeftRef(const QString &src, const QString &whitespace = {}) {
return trimmedRef(src, whitespace, TrimmedLeft);
}
QStringRef trimmedRightRef(const QString &src, const QString &whitespace = {}) {
return trimmed(src, whitespace, TrimmedRight);
}
QString trimmed(const QString &src, const QString &whitespace,
TrimmedOptions opt = TrimmedLeft | TrimmedRight) {
return trimmedRef(src, whitespace, opt);
}
QString trimmedLeft(const QString &src, const QString &whitespace = {}) {
return trimmedRef(src, whitespace, TrimmedLeft);
}
QString trimmedRight(const QString &src, const QString &whitespace = {}) {
return trimmedRef(src, whitespace, TrimmedRight);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With