QRegExp не соответствует, хотя regex101.com соответствует

Мне нужно извлечь некоторые данные из строки с простым синтаксисом. Синтаксис таков:

_IMPORT:[any text] - [HEX number] #[decimal number]

Поэтому я создал регулярное выражение, которое вы можете увидеть ниже в коде:

 //SYNTAX:  _IMPORT:%1 - %2 #%3
 static const QRegExp matchImportLink("^_IMPORT:(.*?) - ([A-Fa-f0-9]+) #([0-9]+)$");
 QRegExp importLink(matchImportLink);
 QString qtWtf(importLink.pattern());
 const int index = importLink.indexIn(mappingName);

 qDebug()<< "Input string: "<<mappingName;
 qDebug()<< "Regular expression:"<<qtWtf;
 qDebug()<< "Result: "<< index;

По какой-то причине это не работает, я получаю этот вывод:

Input string:  "_IMPORT:ddd - 92806f0f96a6dea91c37244128f7d00f #0"
Regular expression: "^_IMPORT:(.*?) - ([A-Fa-f0-9]+) #([0-9]+)$"
Result:  -1

Я даже пытался удалить якоря ^ и $, но это не помогло, да и нежелательно. Раздражает то, что это регулярное выражение отлично работает, если я скопирую вывод в regex101.com, как вы можете видеть здесь: https://regex101.com/r/oT6cY3/1

Кто-нибудь может объяснить, что здесь не так? Я наткнулся на ошибку Qt? Я использую Qt 5.6. Есть ли обходной путь для этого?


person Tomáš Zato - Reinstate Monica    schedule 15.08.2016    source источник
comment
Не имеет опыта работы с регулярными выражениями. А вот круглые скобки после IMPORT:**(** и все остальные) для меня выглядят странно. - Я ожидаю, что регулярное выражение будет соответствовать символу (, которого нет в выражении. Но если у них есть regexp-семантика, просто забудьте мой комментарий.   -  person Bernhard Heinrich    schedule 15.08.2016
comment
@BernhardHeinrich Они используют (цитируя документы) богатый Perl-подобный синтаксис сопоставления шаблонов, что означает, что группы захвата существуют, и я использовал их в прошлом без проблем.   -  person Tomáš Zato - Reinstate Monica    schedule 15.08.2016
comment
Я вижу, что изменение (.*?) на (.*) помогает, но не знаю почему. Смена движка регулярного выражения тоже не помогает...   -  person mike.dld    schedule 15.08.2016
comment
@ mike.dld Похоже, они понимают это наоборот, потому что (.*?) не является жадным, чтобы предотвратить сопоставление части `- [hex]`.   -  person Tomáš Zato - Reinstate Monica    schedule 15.08.2016
comment
Просто используйте уже QRegularExpression! :) QRegExp поддерживает очень ограниченный синтаксис шаблонов (в частности: он не поддерживает нежадные квантификаторы). Вместо этого QRegularExpression поддерживает PCRE.   -  person peppe    schedule 15.08.2016
comment
@peppe спасибо, что упомянули об этом. Я буду смотреть в него. Я думаю, они должны упомянуть об этом в QRegExp документах...   -  person Tomáš Zato - Reinstate Monica    schedule 16.08.2016
comment
doc.qt.io/qt-5/qregexp.html Примечание. В В Qt 5 новый класс QRegularExpression обеспечивает совместимую с Perl реализацию регулярных выражений и рекомендуется вместо QRegExp.   -  person peppe    schedule 16.08.2016
comment
@peppe Проблема в том, что версия документа 4.8 QRegExp занимает первое место в Google. Я думаю, что должна быть какая-то ссылка на последнюю версию для всех документов...   -  person Tomáš Zato - Reinstate Monica    schedule 16.08.2016
comment
Да, это определенно плохо. bugreports.qt.io/browse/QTWEBSITE-721   -  person peppe    schedule 16.08.2016


Ответы (1)


Похоже, что Qt не распознает квалификатор *? как действительный. Проверьте метод QRegExp::isValid() на свой шаблон. В моем случае это не сработало из-за этого. И в документации сказано, что любой недопустимый шаблон никогда не будет совпадать.

Итак, первое, что я попробовал, это пропустить ?, который идеально соответствует предоставленной вами строке со всеми группами захвата. Вот мой код.

QString str("_IMPORT:ddd - 92806f0f96a6dea91c37244128f7d00f #0");
QRegExp exp("^_IMPORT:(.*) - ([A-Fa-f0-9]+) #([0-9]+)$");

qDebug() << "pattern:" << exp.pattern();
qDebug() << "valid:" << exp.isValid();
int pos = 0;
while ((pos = exp.indexIn(str, pos)) != -1) {
    for (int i = 1; i <= exp.captureCount(); ++i)
        qDebug() << "pos:" << pos << "len:" << exp.matchedLength() << "val:" << exp.cap(i);
    pos += exp.matchedLength();
}

И вот результат.

pattern: "^_IMPORT:(.*) - ([A-Fa-f0-9]+) #([0-9]+)$"
valid: true
pos: 0 len: 49 val: "ddd"
pos: 0 len: 49 val: "92806f0f96a6dea91c37244128f7d00f"
pos: 0 len: 49 val: "0"

Протестировано с использованием Qt 5.6.1.

Также обратите внимание, что вы можете установить жадную оценку, используя QRegExp::setMinimal(bool).

person maxik    schedule 15.08.2016
comment
Большое спасибо за этот хороший ответ! :) Есть ли у вас какие-либо идеи, является ли это поведение преднамеренным или нет? .*? очень широко распространен в RegExp, поэтому я нахожу удивительным, что он недействителен... - person Tomáš Zato - Reinstate Monica; 15.08.2016
comment
Взгляните на QRegularExpression - person Sebastian Lange; 16.08.2016