QString trim 行开头或结尾的非空白字符

QString trim non-whitespace characters from line begin or end

有些语言有 ltrim(), rtrim() 函数,任意字符到 trim,但是 Qt 中的 QString 目前似乎没有类似的东西。如何使用当前功能实现这样的功能?正则表达式?

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

超载

trimmed(QByteArray &chars)

到 trim 任意字符,不仅是空格。应该很方便。

如果您认为该功能很重要,那么您可以 post 在 https://bugreports.qt.io/. If you look at qstring.cpp 上提出功能请求,您会发现该功能相当简单,您可以更快地创建自己的自定义功能。

您可以 trim 空格、\n\rQString::simplified();

qDebug() << QString(" lots\t of\nwhitespace\r\n ").simplified();

Output: lots of whitespace

或者如果你喜欢 trim 自定义字母,你可以使用 QString::removeQRegExp:

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 不是存储 QChars 的方法:QString 是。鉴于此,实施并不复杂。使用ws.containsstd::binary_search之间的切换点应根据基准来选择。

trimmedReftrimmedLeftReftrimmedRightRef 是不复制源字符串的优化。当字符串的修剪版本不会比源字符串长寿时可以使用它们 - 这避免了复制。

#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);
}