songvan
songvan

Reputation: 379

How to replace QRegExp in a string?

I have a string. For example:

QString myString = "Today is Tuesday";

The requirement is: when user types a string, if that string is contained in myString, then that part in the myString should be bold, and case insensitive (Qt::CaseInsensitive), but the format of myString should remain (upper case characters should be upper case and lower case characters should be lower case).

For example:

This is my function:

void myClass::setBoldForMatching( const QString &p_text )
{
  QRegExp regExp( p_text, Qt::CaseInsensitive, QRegExp::RegExp );
  if ( !p_text.isEmpty() )
  {       
    if ( myString.contains( regExp ) )
    {
      myString = myString.replace( p_text, QString( "<b>" + p_text + "</b>" ), Qt::CaseInsensitive );
    }
  }
}

This function is wrong because

user types t -> today is tuesday.

What I need is Today is Tuesday

How should I update my function?

Upvotes: 5

Views: 2882

Answers (3)

scopchanov
scopchanov

Reputation: 8419

Solution

Change your setBoldForMatching like this:

void myClass::setBoldForMatching(const QString &p_text)
{
    QRegExp regExp(p_text, Qt::CaseInsensitive, QRegExp::RegExp);
    QString str = myString;
    
    if (p_text.isEmpty()) {
        label->setText(myString);
        return;
    }
    
    int count = 0;
    int pos = 0;
    QStringList matches;
    
    while ((pos = regExp.indexIn(str, pos)) != -1) {
        ++count;
        pos += regExp.matchedLength();
        matches.append(regExp.capturedTexts());
    }
    
    foreach (const QString &match, matches) {
        str.replace(match, "<b>" + match + "</b>");
    }
}

I have decided to keep the original content of myString, so the result is contained in str instead.

Example

I have prepared a small example for you in order to demonstrate the result. The full code is available on GitHub.

Result

Screenshot

Upvotes: 2

Toby Speight
Toby Speight

Reputation: 30930

We can use a different QString::replace(), which accepts a QRexExp, to substitute all occurrences. The key to this is that we need a capture group in order to replace the original text in the substitution, using a back-reference (\1):

#include <QRegExp>

QString setBoldForMatching(QString haystack, const QString& needle)
{
    if (needle.isEmpty()) return haystack;
    const QRegExp re{"("+QRegExp::escape(needle)+")", Qt::CaseInsensitive};
    return haystack.replace(re, "<b>\\1</b>");
}

Demo

#include <QDebug>
int main()
{
    qInfo() << setBoldForMatching("THIS DAY (today) is Tuesday.", "Day");
}

THIS DAY (today) is Tuesday.

Upvotes: 6

Stanley F.
Stanley F.

Reputation: 1998

Replacing a match with p_text will always change the case to the one of p_text. So you have to do the replacement step by step, like this:

void myClass::setBoldForMatching(const QString &p_text) {
    QRegExp regExp( p_text, Qt::CaseInsensitive, QRegExp::FixedString );

    QString start = "<b>";
    QString stop = "</b>";

    int i=-1;
    while (-1 != (i=myString.indexOf(regExp,i+1))) {
        myString.insert(i, start);
        i += start.size();
        i += p_text.size();
        myString.insert(i, stop);
        i += stop.size();
    }
}

As you can see, with this code, the start and stop tags will be inserted before and after the match, without changing the matched sub-string itself.

Here are some test cases:

  • Today is Tuesday + tu --> Today is Tuesday
  • Today is Tuesday + ES --> Today is Tuesday
  • Today is Tuesday + aY --> Today is Tuesday
  • Today is Tuesday + t --> Today is Tuesday

  • Today is today + To --> Today is today

Upvotes: 2

Related Questions