QRegularExpression ленивое сопоставление не работает для очень больших строк
Я использую QRegularExpression
в Qt 5.10.1 извлечь фрагменты текста из файлов, которые связаны верхним и нижним колонтитулами. Например, рассмотрим следующий текст:
...
begin
some text
some more text
...
end
...
begin
etc.
Затем я использовал бы следующее регулярное выражение для захвата фрагмента текста:
^begin\n([\s\S]+?)^end
Здесь нет ничего необычного. Проблема в том, что если текстовый раздел очень большой (более 100 тыс. Строк), регулярное выражение перестает создавать совпадение. Я пробовал поиск в другом текстовом редакторе (TextPad), и он отлично работает, поэтому я подозреваю, что это происходит из-за некоторой константы MAX_SIZE в QRegularExpression
или, скорее всего, используемую библиотеку 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;
}
1 ответ
Так получается, что библиотека PCRE2, реализованная QRegularExpression
имеет MATCH_LIMIT
переменная по умолчанию 10 000 000 (в файле config.h библиотеки). Это сочетается с природой "ленивого" соответствия (когда продвижение поиска вперед на один символ считается совпадением с MATCH_LIMIT
) объясняет, что я видел. Это прискорбно, потому что я думал, что производительность ленивого сопоставления была очень хорошей в этом примере.
Библиотека PCRE2 позволяет MATCH_LIMIT
переменная, которая будет переопределена для поиска, но эта функция не реализована в QRegularExpression
, Я мог бы исправить библиотеку Qt или изменить библиотеку PCRE2 по умолчанию и пересобрать, но сейчас я нашел альтернативное (и гораздо более сложное для понимания) регулярное выражение, основанное на хорошей статье здесь:
^begin\n((?:[^\n]++|\n(?!end))*+)\nend