Russian Qt Forum

Qt => Вопросы новичков => Тема начата: billy4685 от Июль 12, 2021, 15:04



Название: Почему метод QString::count(QRegExp) не находит строки типа "(текст", "текст)"?
Отправлено: billy4685 от Июль 12, 2021, 15:04
Добрый день.

Когда-то был реализовал поиск текста по справке. Пользовался регулярными (QRegExp) выражениями:
   QRegExp("\\bтекст\\b") для поиска типа "только слова целиком";
   QRegExp("текст")  если не учитывая слова целиком.

Чтобы учитывать регистр использовал метод QRegExp::setCaseSensitivity(Qt::CaseSensitivity cs).
Поиск по тексту проводил методом QString::count(const QRegularExpression &re) const.

На днях заметил, что текст типа "(текст" или "текст)" моя программа не находит. В то же время, текст типа "(текст)" находит.
Регулярные выражения использовал лишь из-за того, чтобы можно было искать текст учитывая поиск "только слова целиком".
Понимаю, что проблема в регулярном выражении. Но вот понять как правильно составить регулярное выражение для поиска всевозможного
текста не могу понять.

Ниже прикрепляю небольшой пример. Может кто-то уже решал подобную проблему. Буду рад любым советам.

Исходники программы:
FindSubstring.pro
Код:
QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = FindSubstring
TEMPLATE = app

SOURCES += main.cpp\
        mainwindow.cpp

HEADERS  += mainwindow.h

FORMS    += mainwindow.ui

main.cpp
Код:
#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow w;
w.show();

return app.exec();
}

mainwindow.h
Код:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();

protected:
void changeEvent(QEvent *e);

public slots:
void substring_search();

private:
Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

mainwindow.cpp
Код:
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
  QMainWindow(parent),
  ui(new Ui::MainWindow)
{
ui->setupUi(this);

ui->source_text->setFont(QFont("Times New Roman", 12, QFont::Normal));
ui->source_text->setText("Беспилотный летательный аппарат (БЛА, БПЛА; в разговорной речи также «беспилотник» или «дрон», от англ. drone — трутень) — "
"летательный аппарат без экипажа на борту."
"БПЛА могут обладать разной степенью автономности — от управляемых дистанционно до полностью автоматических, а также различаться "
"по конструкции, назначению и множеству других параметров. Управление БПЛА может осуществляться эпизодической подачей команд или "
"непрерывно — в последнем случае БПЛА называют дистанционно-пилотируемым летательным аппаратом (ДПЛА). БПЛА могут решать разведывательные "
"задачи (на сегодня это основное их предназначение), применяться для нанесения ударов по наземным и морским целям, перехвата воздушных целей, "
"осуществлять постановку радиопомех, управления огнём и целеуказания, ретрансляции сообщений и данных, доставки грузов.");


QFont standart_font(QFont("Arial", 9, QFont::Normal));
ui->case_sensitive_ch->setFont(standart_font);
ui->whole_words_ch->setFont(standart_font);
ui->find_but->setFont(standart_font);
ui->result_find_lb->setFont(standart_font);
ui->find_edit->setFont(standart_font);

connect(ui->find_but, SIGNAL(clicked(bool)), this, SLOT(substring_search()));

}

MainWindow::~MainWindow()
{
delete ui;
}

void MainWindow::changeEvent(QEvent *e)
{
QMainWindow::changeEvent(e);
switch (e->type()) {
  case QEvent::LanguageChange:
    ui->retranslateUi(this);
    break;
  default:
    break;
  }
}

void MainWindow::substring_search()
{
  ui->result_find_lb->setText("");

  if(ui->find_edit->text() == "")
    {
      ui->result_find_lb->setText("Введите текст для поиска!");
    }
  else
    {
      QString find_text;

      if(ui->whole_words_ch->isChecked() == true)
find_text = QString("\\b%1\\b").arg(ui->find_edit->text());
      else
find_text = QString("%1").arg(ui->find_edit->text());

      QRegExp reg_find_text(find_text);

      if(ui->case_sensitive_ch->isChecked() == true)
reg_find_text.setCaseSensitivity(Qt::CaseSensitive);
      else
reg_find_text.setCaseSensitivity(Qt::CaseInsensitive);

      reg_find_text.setMinimal(true);

      int count_find = ui->source_text->document()->toPlainText().count(reg_find_text);

      if(count_find == 0)
ui->result_find_lb->setText("В данном тексте нет такой подстроки.");
      else
ui->result_find_lb->setText(QString("В данном тексте введенная вами строка "
   "встречается %1 раз.").arg(count_find));
    }
}

Скрин програмки и архив:


Название: Re: Почему метод QString::count(QRegExp) не находит строки типа "(текст", "текст)"?
Отправлено: kambala от Июль 12, 2021, 17:52
потому что скобка — это спецсимвол регулярок (один из), обозначающий «захватывающую группу». скобки должны быть сбалансированы для того, чтобы регулярка была валидная.

для включения литеральной скобки (и прочих особых символов) в искомое выражение, необходимо ее экранировать с помощью обратной косой черты: \(. (в С++ строке саму обратную косую черту также надо экранировать: "\\(")

чтобы не возиться с ручным экранированием, есть удобный метод QRegularExpression::escape(): https://doc.qt.io/qt-5/qregularexpression.html#escape


Название: Re: Почему метод QString::count(QRegExp) не находит строки типа "(текст", "текст)"?
Отправлено: billy4685 от Июль 13, 2021, 13:10
kambala, благодарю за ответ.