10

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

László Papp
  • 51,870
  • 39
  • 111
  • 135
user3136871
  • 245
  • 2
  • 3
  • 8

4 Answers4

22

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 at a string

darda
  • 3,597
  • 6
  • 36
  • 49
vahancho
  • 20,808
  • 3
  • 47
  • 55
  • Resulting string should be: "this at a string" – SketchBookGames Aug 22 '14 at 17:16
  • 1
    This does not work if you are trying to match a QRegularExpression, as it has no "size()". – Anon Dec 12 '15 at 14:47
  • @Akiva, `QRegExp` has `matchedLength()`, and `QRegularExpressionMatch` has `capturedLength()` - what's the problem? – Toby Speight Jul 05 '16 at 17:45
  • @TobySpeight back references in newString (like \1) don't work, though. – Sascha Jan 25 '18 at 13:43
  • 1
    @Akiva you can use pos and cap methods of the regular expression to get the text position and the text size. Just like I've explained in https://stackoverflow.com/questions/34612750/qstring-remove-first-occurance-of-regular-expression/59314385#59314385 – kato2 Dec 13 '19 at 12:11
3

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" 
Community
  • 1
  • 1
László Papp
  • 51,870
  • 39
  • 111
  • 135
0

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);
        }
    }
}
kcrossen
  • 159
  • 2
  • 4
-1
//------------------------------------------------------------------
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
  • Although this code may be help to solve the problem, providing additional context regarding _why_ and/or _how_ it answers the question would significantly improve its long-term value. Please [edit] your answer to add some explanation. – Toby Speight Jul 05 '16 at 17:41