Trivially:
int number_of_hashes(const QString &s) {
int i, l = s.size();
for(i = 0; i < l && s[i] == '#'; ++i);
return i;
}
In other languages (mostly interpreted ones) you have to fear iteration over characters as it's slow, and delegate everything to library functions (generally written in C). In C++ iteration is perfectly fine performance-wise, so a down-to-earth for
loop will do.
Just for fun, I made a small benchmark comparing this trivial method with the QRegularExpression
one from OP, possibly with the RE object cached.
#include <QCoreApplication>
#include <QString>
#include <vector>
#include <QElapsedTimer>
#include <stdlib.h>
#include <iostream>
#include <QRegularExpression>
int number_of_hashes(const QString &s) {
int i, l = s.size();
for(i = 0; i < l && s[i] == '#'; ++i);
return i;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
const int count = 100000;
std::vector<QString> ss;
for(int i = 0; i < 100; ++i) ss.push_back(QString(rand() % 10, '#') + " foo ## bar ###");
QElapsedTimer t;
t.start();
unsigned tot = 0;
for(int i = 0; i < count; ++i) {
for(const QString &s: ss) tot += number_of_hashes(s);
}
std::cerr<<"plain loop: "<<t.elapsed()*1000./count<<" ns\n";
t.restart();
for(int i = 0; i < count; ++i) {
for(const QString &s: ss) tot += QRegularExpression("^[#]*").match(s).capturedLength();
}
std::cerr<<"QRegularExpression, rebuilt every time: "<<t.elapsed()*1000./count<<" ns\n";
QRegularExpression re("^[#]*");
t.restart();
for(int i = 0; i < count; ++i) {
for(const QString &s: ss) tot += re.match(s).capturedLength();
}
std::cerr<<"QRegularExpression, cached: "<<t.elapsed()*1000./count<<" ns\n";
return tot;
}
As expected, the QRegularExpression
-based one is two orders of magnitude slower:
plain loop: 0.7 ns
QRegularExpression, rebuilt every time: 75.66 ns
QRegularExpression, cached: 24.5 ns