Question

Is there simple way of replacing only first occurrence of some substring by other substring in QString? It can be at any position.

Was it helpful?

Solution

You could try this:

QString str("this is a string"); // The initial string.
QString subStr("is"); // String to replace.
QString newStr("at"); // Replacement string.

str.replace(str.indexOf(subStr), subStr.size(), newStr);

Resulting string will be:

that is a string

OTHER TIPS

There is no convenience method for the operation you wish to have. However, you can use the following two methods to build your custom operation:

int QString::indexOf(const QString & str, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const

Returns the index position of the first occurrence of the string str in this string, searching forward from index position from. Returns -1 if str is not found.

If cs is Qt::CaseSensitive (default), the search is case sensitive; otherwise the search is case insensitive.

and

QString & QString::replace(int position, int n, const QString & after)

Replaces n characters beginning at index position with the string after and returns a reference to this string.

Note: If the specified position index is within the string, but position + n goes outside the strings range, then n will be adjusted to stop at the end of the string.

Now, putting all that into practice, you could write something as follows:

main.cpp

#include <QString>
#include <QDebug>

int main()
{
    QString initialString = QLatin1String("foo bar baz");
    QString fooString = QLatin1String("foo");
    initialString.replace(initialString.indexOf(fooString),
                          fooString.size(), QLatin1String("stuff"));
    qDebug() << initialString;
    return 0;
}

main.pro

TEMPLATE = app                                         
TARGET = main                                              
QT = core                                              
SOURCES += main.cpp

Build and Run

qmake && make && ./main

Output

"stuff bar baz" 

This is pretty much the way QString::replace(QRegularExpression, ... does it. Since it's possible that literal backslashes could be part of replace pattern, those need to be captured differently. Note that actual replacement happens right-to-left to preserve leftward offset validity. It's possible to put this more compactly, but easier to debug in this form.

QRegularExpression regex = QRegularExpression(regex_pattern);

if (regex.isValid() and
    (regex_pattern.length() > 0)) {
    QRegularExpressionMatchIterator regex_iterator =
                                      regex.globalMatch(target_text, Apply_Target_Offset,
                                                        QRegularExpression::PartialPreferCompleteMatch);
    if (regex_iterator.hasNext()) {
        // At least one found
        QRegularExpressionMatch match = regex_iterator.next();
        if (match.hasMatch() and (not match.hasPartialMatch())) {
            // This is the first match, and it's complete
            int match_begin = match.capturedStart();
            int match_end = match.capturedEnd();
            int match_length = match.capturedLength();

            QStringList captured;
            const int capture_groups_count = regex.captureCount() + 1;
            for (int capture_group_idx = 0; capture_group_idx < capture_groups_count; ++capture_group_idx) {
                captured.append(match.captured(capture_group_idx));
            }

            QString replace_pattern = Apply_Replace_Pattern->toPlainText();
            QString replace_text = replace_pattern;
            QList<QRegularExpressionMatch> replace_pattern_match_list;
            QRegularExpression replace_pattern_regex = QRegularExpression("(?:\\\\\\\\)+|(?:\\\\(\\d+))");
            if (replace_pattern_regex.isValid()) {
                QRegularExpressionMatchIterator replace_pattern_regex_iterator =
                                                  replace_pattern_regex.globalMatch(replace_pattern);
                while (replace_pattern_regex_iterator.hasNext()) {
                    QRegularExpressionMatch replace_pattern_match = replace_pattern_regex_iterator.next();
                    bool no_error;
                    replace_pattern_match.captured().right(1).toInt(&no_error);
                    // Only accept backreferences w/ numbers
                    if (no_error) replace_pattern_match_list.append(replace_pattern_match);
                }

                while (replace_pattern_match_list.count() > 0) {
                    QRegularExpressionMatch replace_pattern_match = replace_pattern_match_list.takeLast();
                    int cap_idx = replace_pattern_match.captured(1).toInt();
                    if (cap_idx < captured.count()) {
                        replace_text.replace(replace_pattern_match.capturedStart(),
                                             (replace_pattern_match.capturedEnd() -
                                              replace_pattern_match.capturedStart()),
                                             captured[cap_idx]);
                    }
                }

                // Render '\' characters properly
                replace_text.replace("\\\\", "\\");
            }

            target_text.replace(match_begin, (match_end - match_begin), replace_text);
        }
    }
}
//------------------------------------------------------------------
QString & replace_first(QString &io_haystack, const QString & sub_str, const QString & new_str)
{
  io_haystack.replace(io_haystack.indexOf(sub_str), sub_str.size(), new_str);
  return io_haystack;
} // replace_first
//------------------------------------------------------------------
QString & replace_first(QString &io_haystack, const QRegularExpression & sub_regx, const QString & new_str)
{
  QRegularExpressionMatch match;
  match = sub_regx.match(io_haystack);
  if (match.hasMatch()) {
    QString sub_str = match.captured(0);
    io_haystack.replace(io_haystack.indexOf(sub_str), sub_str.size(), new_str);
  }
  return io_haystack;
} // replace_first
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top