IT Notes

Регулярные выражения в Qt

Регулярные выражения в Qt реализованы классом QRegExp. Рассмотрим основные варианты его использования на примерах.

Точное совпадение регулярного выражения

В качестве примера рассмотрим регулярное выражение для проверки строки на точное соответствие директиве #include <…>:

#include <QRegExp>
#include <QStringList>
#include <QDebug>

int main() {
    QRegExp re( "#include <[^>]+>" );

    QStringList strings = QStringList() <<
                       "#include <iostream>" <<
                       "    #include      <iostream>     " <<
                       "#include \"iostream\"" <<
                       "#define <iostream>";


    foreach( const QString& str, strings ) {
        qDebug() << ( re.exactMatch( str ) ? "matched" : "mismatched" ) << ":" << str;
    }

    return 0;
}

В результате выполнения этого кода на консоли будет выведено (кроме комментариев, которые добавлены отдельно):

matched : "#include <iostream>"                  // Все правильно
mismatched : "    #include      <iostream>     " // Лишние пробелы
mismatched : "#include "iostream""               // Вместо < использовано "
mismatched : "#define <iostream>"                // Нам нужен include, а не define

Совпадение произошло лишь в первом случае, поскольку приведенное регулярное выражение учитывает только ТОЧНОЕ совпадение. Этот вариант использования регулярных выражений подойдет для проверки ip-адресов, MAC-адресов, адресов электронной почты и т.д.

Если вам нужно проверить не точное совпадение с регулярным выражением, а просто его наличие где-либо в строке, то воспользуйтесь функцией QString::contains(), которая предназначена именно для этого.

Найти все совпадения для регулярного выражения

Следующий пример демонстрирует способ поиска с помощью регулярных выражений всех упоминаний #include <…>:

#include <QRegExp>
#include <QStringList>
#include <QDebug>

static const char* const TEXT =
    "#include <QRegExp>\n"
    "#include <QStringList>\n"
    "#include <QDebug>\n"
    "\n"
    "int main() {\n"
        "QRegExp re( \"#include <([^>]+)>\" );\n"
        "int lastPos = 0;\n"
        "while( ( lastPos = re.indexIn( TEXT, lastPos ) ) != -1 ) {\n"
            "lastPos += re.matchedLength();\n"
            "qDebug() << re.cap( 0 );\n"
        "}\n"
        "return 0;\n"
    "}";


int main() {
    QRegExp re( "#include <([^>]+)>" );

    int lastPos = 0;
    while( ( lastPos = re.indexIn( TEXT, lastPos ) ) != -1 ) {
        lastPos += re.matchedLength();
        qDebug() << re.cap( 0 ) << ":" << re.cap( 1 );
    }

    return 0;
}

Представленный выше код выведет следующее:

"#include <QRegExp>" : "QRegExp"
"#include <QStringList>" : "QStringList"
"#include <QDebug>" : "QDebug"
"#include <([^>" : "([^"

Обратите внимание, что под выбранное регулярное выражение подошли все упоминания #include. Даже то, которое синтаксически является обычной строкой.

Также мы извлекли группу re.cap( 1 ), содержащую текст внутри <…>.

Аналогичным образом с помощью регулярных выражений вы можете искать в тексте номера телефонов; имена файлов и многое другое.

Замена текста по регулярному выражению

С помощью регулярных выражений удобно осуществлять замену фрагментов текста. Рассмотрим пример:

#include <QRegExp>
#include <QStringList>
#include <QDebug>

static const char* const TEXT =
    "#include <QRegExp>\n"
    "#include <QStringList>\n"
    "#include <QDebug>\n"
    "\n"
    "int main() {\n"
        "qDebug() << QString( TEXT ).replace( QRegExp( \"#include <([^>]+)>\" ), \"#include \"\\1\"\" );\n"
        "return 0;\n"
    "}";

int main() {
    qDebug() << QString( TEXT ).replace( QRegExp( "#include <([^>]+)>" ), "#include \"\\1\"" );

    return 0;
}

Записанное регулярное выражение меняет #include <…> на #include "…". На консоль будет выведено следующее:

"#include "QRegExp"
#include "QStringList"
#include "QDebug"

int main() {
qDebug() << QString( TEXT ).replace( QRegExp( "#include "([^"]+)>" ), "#include "\1"" );
return 0;
}"

Такая замена осуществляется с помощью группы в регулярном выражении, обернутой в скобки. Ссылка на группу делается с помощью конструкции вида \\n, где n - номер группы, соответствующей индексу в вызове re.cap( n ).

Этот прием хорошо подойдет для выполнения простых (и не очень) преобразований текста с помощью регулярных выражений, в которых легко выделяются группы.

Похожие публикации

Комментарии

Как на счет актуального для Qt5 QRegularExpression?

Спасибо за комментарий. Думаю, что подобный материал и правда не помешало бы подготовить.

В строке

QRegExp re( "#include <[^>]+>" );

не понятно что за <[^>]+> - это маска какая то? Никогда не встречал подобного. Дайте ссылку на пояснение пожалуйста.

Здравствуйте. Выражение <[^>]+> ищет подстроки, которые начинаются с символа '<' и заканчивается символом '>', но не содержат символа '>' где-нибудь в середине ("[^>]+" - один или более символ, отличный от '>').

Например, в строке "<123><456>" есть два соответствия для <[^>]+>: "<123>" и "<456>", но одно соответствие "<123><456>" для <.+>.

Это связано с тем, что QRegExp по умолчанию работает в режиме "жадного" поиска. Управлять этим свойством можно с помощью функции класса QRegExp - setMinimal().

Mikhail Спасибо за внимание к моей проблеме, но мне все же стоило сразу обратиться к гуглу и, конкретно, к офф. документации. Тема с масками QT слишком обширна для ответа в комментарии. Хотя было бы отлично почитать это на русском. Вот, собственно что я нашел http://doc.qt.io/qt-5/qregexp.html

Anonymous:

Mikhail Спасибо за внимание к моей проблеме, но мне все же стоило сразу обратиться к гуглу и, конкретно, к офф. документации. Тема с масками QT слишком обширна для ответа в комментарии. Хотя было бы отлично почитать это на русском. Вот, собственно что я нашел http://doc.qt.io/qt-5/qregexp.html

Если Вы пользуетесь Qt 5, то рекомендую обратить внимание на QRegularExpression: моя статья, официальная документация.