QRegularExpression 惰性匹配不适用于非常大的字符串
QRegularExpression lazy matching not working for very large strings
我在 Qt 5.10.1 中使用 QRegularExpression
从由页眉和页脚绑定的文件中提取文本部分。例如,考虑以下文本:
...
begin
some text
some more text
...
end
...
begin
etc.
然后我会使用以下正则表达式来捕获一段文本:
^begin\n([\s\S]+?)^end
这里没有什么不寻常的。问题是如果文本部分非常大(超过 10 万行),那么正则表达式将停止生成匹配项。我尝试在不同的文本编辑器 (TextPad) 中进行搜索,但效果很好,所以我怀疑这是由于 QRegularExpression
中的某种 MAX_SIZE 常量或更可能是它使用的 PCRE2 库造成的。但我不知道去哪里看,或者这是否是我可以调整的?或者这可能被认为是一个错误?
下面是一些可用于演示我的问题的代码。对我来说,它在 100,000 行(10,000,000 字节)时爆炸。
QString s = "This line of text is exactly one hundred bytes long becuase it's a nice round number for this test.\n";
QRegularExpression re = QRegularExpression(R"(^begin\n([\s\S]+?)^end)", QRegularExpression::MultilineOption);
qDebug() << "start check:";
for (int i=10000; i<200000; i=i+1000) {
QString test = "begin\n" + s.repeated(i) + "end\n";
QRegularExpressionMatch match = re.match(test);
if (!match.hasMatch()) {
qDebug() << "lazy match failed - trying greedy match";
re.setPattern(R"(^begin\n([\s\S]+)^end)");
QRegularExpressionMatch match = re.match(test);
qDebug() << match.hasMatch();
break;
}
qDebug() << i;
}
原来 QRegularExpression
实现的 PCRE2 库有一个默认为 10,000,000 的 MATCH_LIMIT
变量(在库的 config.h 文件中)。这与 'lazy' 匹配的性质相结合(向前搜索一个字符算作 MATCH_LIMIT
的匹配)解释了我所看到的。这很不幸,因为我认为在这个例子中惰性匹配的性能非常好。
PCRE2 库允许覆盖 MATCH_LIMIT
变量以进行搜索,但此功能未在 QRegularExpression
中实现。我可以修补 Qt 库或更改 PCRE2 库默认值并重新构建,但现在我已经找到了一个基于一篇好文章 here:
的替代(并且更难理解)正则表达式
^begin\n((?:[^\n]++|\n(?!end))*+)\nend
我在 Qt 5.10.1 中使用 QRegularExpression
从由页眉和页脚绑定的文件中提取文本部分。例如,考虑以下文本:
...
begin
some text
some more text
...
end
...
begin
etc.
然后我会使用以下正则表达式来捕获一段文本:
^begin\n([\s\S]+?)^end
这里没有什么不寻常的。问题是如果文本部分非常大(超过 10 万行),那么正则表达式将停止生成匹配项。我尝试在不同的文本编辑器 (TextPad) 中进行搜索,但效果很好,所以我怀疑这是由于 QRegularExpression
中的某种 MAX_SIZE 常量或更可能是它使用的 PCRE2 库造成的。但我不知道去哪里看,或者这是否是我可以调整的?或者这可能被认为是一个错误?
下面是一些可用于演示我的问题的代码。对我来说,它在 100,000 行(10,000,000 字节)时爆炸。
QString s = "This line of text is exactly one hundred bytes long becuase it's a nice round number for this test.\n";
QRegularExpression re = QRegularExpression(R"(^begin\n([\s\S]+?)^end)", QRegularExpression::MultilineOption);
qDebug() << "start check:";
for (int i=10000; i<200000; i=i+1000) {
QString test = "begin\n" + s.repeated(i) + "end\n";
QRegularExpressionMatch match = re.match(test);
if (!match.hasMatch()) {
qDebug() << "lazy match failed - trying greedy match";
re.setPattern(R"(^begin\n([\s\S]+)^end)");
QRegularExpressionMatch match = re.match(test);
qDebug() << match.hasMatch();
break;
}
qDebug() << i;
}
原来 QRegularExpression
实现的 PCRE2 库有一个默认为 10,000,000 的 MATCH_LIMIT
变量(在库的 config.h 文件中)。这与 'lazy' 匹配的性质相结合(向前搜索一个字符算作 MATCH_LIMIT
的匹配)解释了我所看到的。这很不幸,因为我认为在这个例子中惰性匹配的性能非常好。
PCRE2 库允许覆盖 MATCH_LIMIT
变量以进行搜索,但此功能未在 QRegularExpression
中实现。我可以修补 Qt 库或更改 PCRE2 库默认值并重新构建,但现在我已经找到了一个基于一篇好文章 here:
^begin\n((?:[^\n]++|\n(?!end))*+)\nend