【问题标题】:How to replace QRegExp in a string?如何替换字符串中的 QRegExp?
【发布时间】:2019-02-02 20:58:59
【问题描述】:

我有一个字符串。例如:

QString myString = "Today is Tuesday";

要求是:当用户键入一个字符串时,如果该字符串包含在myString中,那么myString中的那部分应该是粗体,并且不区分大小写(Qt::CaseInsensitive),但是@987654325的格式@ 应保留(大写字符应为大写,小写字符应为小写)。

例如:

  • 用户类型:tu -> 今天是星期二esday
  • 用户类型:ES -> 今天是星期二esday
  • 用户类型:aY -> Today 是星期二ay

这是我的功能:

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 );
    }
  }
}

这个函数是错误的,因为

用户类型 t -> today 是 tuesday。

我需要的是T今天是T星期二

我应该如何更新我的函数?

【问题讨论】:

  • 你没有描述所有可能的情况。如果 myString 将是“Today is today”并且用户键入“To”会发生什么
  • 这个应该是粗体的文本在哪里?是QTextEdit 还是别的什么?使用QTextDocumentQTextCursor可以比添加这个html标签更有效和简单。

标签: c++ qt qstring qregexp


【解决方案1】:

我们可以使用一个不同的QString::replace(),它接受一个QRexExp,来替换所有的出现。关键是我们需要一个捕获组,以便使用反向引用 (\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>");
}

演示

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

THIS DAY(到day)是星期二day

【讨论】:

  • 哇,您的解决方案让我阅读了反向引用。这对我来说是新的。非常感谢!
  • 对此我还有一个问题。如果我使用 QRegularExpression,我应该如何翻译你的答案?
  • 这可能值得创建一个新问题(如果您找不到现有问题)。
【解决方案2】:

p_text 替换匹配项将始终将大小写更改为p_text。所以你必须一步一步地进行替换,像这样:

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();
    }
}

如你所见,使用这段代码,开始和结束标记将在匹配前后插入,而不改变匹配的子字符串本身。

这里有一些测试用例:

  • 今天是周二 + tu --> 今天是周二esday
  • 今天是星期二 + ES --> 今天是星期二esday
  • 今天是星期二 + aY --> Today 是星期二ay
  • 今天是星期二 + t --> T今天是 T星期二

  • 今天是今天 + To --> 天是

【讨论】:

    【解决方案3】:

    解决方案

    像这样更改您的setBoldForMatching

    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>");
        }
    }
    

    我决定保留myString的原始内容,所以结果包含在str中。

    示例

    我为你准备了一个小例子来演示结果。完整代码可在GitHub 获得。

    结果

    【讨论】:

    • 正如我所写,该问题并未描述完整的可能案例。我认为您应该在发布任何答案之前充分了解需要什么
    • @borune,是的,我已经看到了。
    • 为什么是p_text.toLower() 而不仅仅是p_text?我认为转换没有任何好处。此外,问题陈述表明我们想要QRegExp::FixedString 而不是QRegExp::RegExp
    猜你喜欢
    • 2022-01-03
    • 2023-04-09
    • 1970-01-01
    • 2013-11-24
    • 1970-01-01
    • 1970-01-01
    • 2021-11-15
    相关资源
    最近更新 更多