【问题标题】:QT C++ QRegularExpression multiple matchesQT C++ QRegularExpression 多重匹配
【发布时间】:2017-04-13 09:49:17
【问题描述】:

我想使用正则表达式从 QString (.html) 中提取信息。我明确地想使用正则表达式(没有解析器解决方案)和QRegularExpression 类(出于多种原因,例如:Reasons)。

为了简化方面,这里是一个问题等效任务。

构造的源字符串:

<foo><bar s>INFO1.1</bar> </ qux> <peter></peter><bar e>INFO1.2
</bar><fred></ senseless></fred></ xx><lol></lol></foo><bar s>INFO2.1</bar>
</ nothing><endlessSenselessTags></endlessSenselessTags><rofl>
<bar e>INFO2.2</bar></rofl>

*注意:*可能会有更多或更少的信息和额外的无意义标签。 (例如 6 条信息)

通缉:

Info1.1 and Info1.2 and Info2.1 and Info2.2 (e.g. in List)

尝试

1.

QRegularExpression reA(".*<bar [es]>(.*)</bar>.*", QRegularExpression::DotMatchesEverythingOption);

->

INFOa</bar> </ qux> <peter></peter><bar e>INFOb
    </bar><fred></ senseless></fred></ xx><lol></lol></foo><bar s>INFOc</bar>
    </ nothing><endlessSenselessTags></endlessSenselessTags><rofl>
    <bar e>INFOd

2.

QRegularExpression reA("(.*<bar [es]>(.*)</bar>.*)*", QRegularExpression::DotMatchesEverythingOption);

->无意义

问题: 正则表达式始终与整个字符串相关。 &lt;bar s&gt;INFO&lt;/bar&gt;&lt;bar s&gt;INFO&lt;/bar&gt; 将选择第一个 &lt;bar s&gt; 和最后一个 &lt;/bar&gt;。想要的是第一

使用 QRegExp 似乎有一个解决方案,但我想使用 QRegularExpression 来做到这一点。

【问题讨论】:

  • 简单:不要在 html/xml 上使用正则表达式。您应该使用 DOM 库。至于您的正则表达式,它会进行通常的贪婪匹配,因此它将匹配整个字符串中的第一个 bar 和最后一个 bar

标签: c++ regex qt


【解决方案1】:

也许你可以试试这个

QRegularExpression reA("(<bar [se]>[^<]+</bar>)");

QRegularExpressionMatchIterator i = reA.globalMatch(input);
while (i.hasNext()) {
    QRegularExpressionMatch match = i.next();
    if (match.hasMatch()) {
         qDebug() << match.captured(0);
    }
}

这给了我这个输出

"<bar s>INFO1.1</bar>" 
"<bar e>INFO1.2
</bar>" 
"<bar s>INFO2.1</bar>" 
"<bar e>INFO2.2</bar>"  

虽然这个表达式

QRegularExpression reA("((?<=<bar [se]>)((?!</bar>).)+(?=</bar>))",
                       QRegularExpression::DotMatchesEverythingOption);

有了这个输入

<foo><bar s>INFO1</lol>.1</bar> </ qux> <peter></peter><bar e>INFO1.2
</bar><fred></ senseless></fred></ xx><lol></lol></foo><bar s>INFO2.1</bar>
</ nothing><endlessSenselessTags></endlessSenselessTags><rofl>
<bar e>INFO2.2</bar></rofl>

给我作为输出

"INFO1</lol>.1" 
"INFO1.2
" 
"INFO2.1" 
"INFO2.2"

【讨论】:

  • 谢谢,我正在寻找 QRegularExpressionMatchIterator 和 globalMatch。但是如果“INFO1.1”也可以包含一个“1.1”。我尝试使用“(?!表达式)”运算符,但这似乎不起作用。我试过&lt;bar [se]&gt;(?!&lt;/td&gt;).+)。需要:“INFO1.1”、“INFO1.2”等?
【解决方案2】:

我正在添加一个新的类似答案,因为令人烦恼的是缺少处理所有指定捕获组的 QRegularExpression 答案,而不是按名称。我只是希望能够指定捕获组并仅获得这些结果,而不是整个厨房水槽。当盲目地抓取捕获组 0 时,这会成为一个问题,这几乎是所有关于 SO 的答案都为 QRegularExpressions 所做的,具有多个结果。此答案返回列表中所有指定的捕获组,如果未指定捕获组,则返回捕获组 0 以进行整个正则表达式匹配。

我在 Gist 上创建了 this simplified code-snippet,但并未直接解决这个问题。如果一个差异确实解决了这个特定问题,下面的示例应用程序。

#include <QCoreApplication>
#include <QRegularExpressionMatch>
#include <QStringList>
#include <iostream>
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QStringList results;
    QRegularExpression this_regex("<bar \\w>(.*?)</bar>");
    QString test_string =   "<foo><bar s>INFO1.1</bar> </ qux> <peter></peter><bar e>INFO1.2\n\
                             </bar><fred></ senseless></fred></ xx><lol></lol></foo><bar s>INFO2.1</bar>\n\
                             </ nothing><endlessSenselessTags></endlessSenselessTags><rofl>\n\
                             <bar e>INFO2.2</bar></rofl>\n";

    if(!this_regex.isValid())
    {
        std::cerr << "Invalid regex pattern: " << this_regex.pattern().toStdString() << std::endl;
        return -2;
    }

    for (int i = 0; i < this_regex.captureCount()+1; ++i)
    {
        // This skips storing capture-group 0 if any capture-groups were actually specified.
        // If they weren't, capture-group 0 will be the only thing returned.    
        if((i!=0) || this_regex.captureCount() < 1)
        {
            QRegularExpressionMatchIterator iterator = this_regex.globalMatch(test_string);    
            while (iterator.hasNext())
            {
                QRegularExpressionMatch match = iterator.next();    
                QString matched = match.captured(i);    
                // Remove this if-check if you want to keep zero-length results
                if(matched.length() > 0){results << matched;}
            }
        }
    }

    if(results.length()==0){return -1;}

    for(int i = 0; i < results.length(); i++)
    {
        std::cout << results.at(i).toStdString() << std::endl;
    }

    return 0;
}

控制台输出:

 INFO1.1
 INFO2.1
 INFO2.2

对我来说,使用QRegularExpression 处理正则表达式比使用std::regex 的痛苦少,但它们都非常通用且健壮,需要更精细的结果处理。我总是使用我为QRegularExpressions 制作的包装器来快速制作我通常想要利用的那种正则表达式和结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-09
    • 1970-01-01
    • 1970-01-01
    • 2011-06-25
    • 1970-01-01
    相关资源
    最近更新 更多