cbuchart
cbuchart

Reputation: 11575

How to split QString into individual characters and create a new one?

I have a QString and I'd like to generate a new string with all characters separated. One way would be to iterate manually over the string and insert the separator after each character but the last one.

Is there a better method or at least a more direct one without having to implement the loop? For example, in order to use directly as function parameter. If possible, using Qt only.

const QString s("Hello world!");
const QString r(some_separating_function(s));
qDebug() << r;

The expected output would be

"H-e-l-l-o- -w-o-r-l-d-!"

EDIT: I'm self-answering it since I didn't find a better solution in SO and I find it useful. If anyone has a better solution I'll appreciate it.

Upvotes: 0

Views: 3924

Answers (2)

cbuchart
cbuchart

Reputation: 11575

The best way I've found so far is to use the QString::split method with an empty string as separator, which happens to create a QList of individual characters (actually, a QList with 1-character QStrings).

const QString s("Hello world!");
const QString r(s.split("", QString::SkipEmptyParts).join('-'));

Upvotes: 2

Here's one way that doesn't allocate any temporaries:

// https://github.com/KubaO/stackoverflown/tree/master/questions/string-sep-42276882
#include <QtCore>

QString separate1(const QString & string, const QString & separator) {
   QString result;
   result.reserve(string.size() * (1 + separator.size()));
   for (auto ch : string) {
      result.append(ch);
      result.append(separator);
   }
   result.chop(separator.size());
   return result;
}

Alas, QString's copy-on-write still has some overhead, so dealing with the data directly will be even faster:

QString separate(const QString & string, const QString & separator) {
   QString result{string.size() + (string.size()-1) * separator.size(),
                  Qt::Uninitialized};
   auto const end = result.data() + result.size();
   int s{};
   for (auto p = result.data(); p < end;) {
     *p++ = string.at(s++);
      if (Q_LIKELY(p < end))
         for (auto const ch : separator)
            *p++ = ch;
   }
   return result;
}

And to check it out:

int main() {
   auto const separator = QStringLiteral("-");
   auto const source = QStringLiteral("Hello world!");
   auto const compare = QStringLiteral("H-e-l-l-o- -w-o-r-l-d-!");
   Q_ASSERT(separate1(source, separator) == compare);
   Q_ASSERT(separate(source, separator) == compare);
}

Upvotes: 1

Related Questions