QT C++ QRegularExpression 多重匹配

9
我希望使用正则表达式从一个QString(.html)中提取信息。我明确地想要使用Regex(不使用解析器解决方案)和类QRegularExpression(出于多种原因,例如:原因)。
为了简化问题,这里是一个等效的任务。 构造源字符串:
<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>

注意:INFO可能会多或少,还有一些无用的标签。(例如6个INFO)
需要翻译的内容:
想要:Info1.1和Info1.2以及Info2.1和Info2.2(例如在列表中)
尝试:
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);

->毫无意义

问题: 正则表达式总是与整个字符串相关。例如<bar s>INFO</bar><bar s>INFO</bar>会选择第一个<bar s>和最后一个</bar>。想要的是第一个

使用QRegExp似乎有解决方案,但我想用QRegularExpression来实现。


简单来说,你不应该在HTML/XML上使用正则表达式,而应该使用DOM库。至于你的正则表达式,它会进行通常的贪婪匹配,因此它将匹配整个字符串中第一个“bar”和最后一个“bar”。 - Marc B
2个回答

13

也许你可以尝试这个

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”也可能包含“<”(另一个标签),你会怎么做呢?例如“Info< /lol>1.1”。我尝试使用“(?! expression)”运算符,但似乎不起作用。我尝试了<bar [se]>(?!</td>).+)。期望结果是:“<bar s>INFO1.1”,“<bar e>INFO1.2”等。? - SearchSpace

2
我要添加一个新的类似答案,因为缺乏处理所有捕获组而不是按名称指定的QRegularExpression答案令人烦恼。我只想指定捕获组并只获取那些结果,而不是整个长串信息。当盲目抓取捕获组0时,这就成为了一个问题,这几乎是SO上所有关于具有多个结果的QRegularExpression的答案所做的。该答案将获取所有指定的捕获组的列表,并且如果未指定任何捕获组,则返回整个正则表达式匹配的捕获组0。
我在Gist上制作了这个简化的代码片段,它没有直接回答这个问题。下面的示例应用程序是一个差异,确实回答了这个特定的问题。
#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要容易得多,但它们都非常通用和健壮,需要更精细的结果处理。我总是使用我为QRegularExpression制作的包装器快速制作我通常想要利用的正则表达式和结果。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接