Qt實現實時正則表達式測試器

算是對boost學習的小結,當然也並沒有完全看完boost,內容很多.只是看了一些常用的內容.

本篇文章將接合對boost正則表達式的學習,完成一個正則表達式測試器.UI藉助了QT的實現.

首先當然是對boost的正則表達式的介紹.

boost有兩個正則表達式解析器.一個是xpressive.還有另外一個叫regex.

沒去了解regex,相比使用方法沒有太大差異.僅就xpressive做簡單的介紹.

xpressive有三個頭文件:

     xpressive_static.h : 靜態的正則匹配方式,可以在編譯期完成.本文不做討論.

     xpressive_dynamic.h : 動態的正則匹配方式.

     xpressive.h : 上面的兩個都包括.

xpressive的三個重要的類 :

     basic_regex : 這個模板類是核心,封裝了正則表達式的解析和編譯的動作.但是使用的時候不直接使用這個類.而是使用它的兩個typedef : cregex(char的正則) 和 sregex(string的正則)

     match_results : 這個模板類保存正則表達式匹配的結果.使用的時候同樣是使用它的兩個typedef : cmatch(同上) 和 smatch(同上).

     sub_match : 這個類只在分詞的時候會用到,作用與match_results類似.

xpressive支持五種基於正則表達式的操作:

     匹配 : 即完整匹配.藉助全局函數regex_match來實現.函數原型爲 bool regex_match(string, match_results &, basic_regex &);其中第一個參數爲源數據,第二個參數是保存匹配後的結果.第三個參數就是正則表達式.

這裏着意瞭解一下第二個參數,既然是完全匹配,爲什麼還需要第二個參數來保存結果呢,因爲第二個參數是一個結果集.重載了[], 下標0保存的是完整匹配的內容,從1開始保存的是匹配的子表達式(即通過小括號括起來的正則表達式匹配到的內容).

     查找 : 只要部分匹配即返回真.函數原型爲 bool regex_search(string, match_results &, basic_regex &); 參數的含義與匹配是一樣的.

     替換 : 使用過sed命令的同學肯定都用過這樣的用法.sed "s/from/to/g" ,在這裏是同樣的意思.需要藉助全局函數 regex_replace(string, basic_regex const &, format);前兩個參數分別是源字符串和正則表達式.最後一個參數format就是需要把basic_regex匹配的內容替換成的字符串.注意可以使用$N來作爲子表達式的佔位符.

     迭代 : cregex_iterator 和 sregex_iterator, 藉助的是match_results類.可以迭代正則表達式匹配的結果.用法也很簡單,只要使用其自身的構造函數即可實現迭代.

regex_iterator(string begin, string end, basic_regex&).第一個參數表示字符串的開頭,第二個參數表示字符串的結尾.第三個參數即爲正則表達式.

     分詞 : 所謂分詞其實也可以理解成一種迭代.不過它所涉及的範圍更廣,不僅可以迭代匹配的內容,還可以迭代不匹配的內容.在使用的時候只要實例化兩個類中的一個即可:cregex_token_iterator 和 sregex_token_iterator.這個功能也是藉助自身構造函數實現的 : regex_token_iterator(string begin, string end, basic_regex, match_type);前三個參數和迭代是一樣的意思,最後一個參數用來標記分詞的內容(把匹配的分出來還是把不匹配的分出來).

本文只是簡單的對boost的正則表達式做了入門級的介紹,如果同學們想要進一步的學習,推薦大家看一下<<boost程序完全開發指南>>,很不錯的一本書,每一個知識點都有一個對應的小例子,很方便學習.

下面來設計一下正則表達式練習器.

1. 實時性,即一邊輸入一邊顯示結果.

2. 結果的顯示方式以高亮的形式進行顯示.

在上面這兩個簡單的需求下,給出實現的代碼:

mywindow.h :

/******************************************************************************
 ** Coypright(C) 2014-2024 () technology Co., Ltd
 **
 ** 文件名 : mywindow.h
 ** 版本號 : 1.0
 ** 描  述 : 
 ** 作  者 : cp3alai
 ** 日  期 : 2015.06.11
 ******************************************************************************/

#include <QObject>
#include <QtGui/QApplication>
#include <QtGui/QDesktopWidget>
#include <QtGui/QWidget>
#include <QtGui/QLabel>
#include <QtGui/QTextEdit>
#include <QtGui/QLineEdit>
#include <QtGui/QPushButton>
#include <QtGui/QGridLayout>
#include <QTextCursor>
#include <QtCore/QTextCodec>

#include <string>
#include <sstream>

#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/xpressive/xpressive.hpp>

using namespace std;
using namespace boost::filesystem;
using namespace boost::xpressive;
namespace fs = boost::filesystem;

class CMyWindow:public QWidget
{
    Q_OBJECT

    public slots:
        void highlightTextMatched(const QString &str);
public:
    CMyWindow(QWidget *parent = 0);

private:
    QLineEdit *m_lineEdit;
    QTextEdit *m_textEdit;
    QPushButton *m_pushButton;
    path m_filename;
    fs::fstream m_fstream;
};


mywindow.cpp :

高亮部分的代碼借鑑子網絡上的代碼.

/******************************************************************************
 ** Coypright(C) 2014-2024 () technology Co., Ltd
 **
 ** 文件名 : mywindow.cpp
 ** 版本號 : 1.0
 ** 描  述 : 
 ** 作  者 : cp3alai
 ** 日  期 : 2015.06.11
 ******************************************************************************/

#include "mywindow.h"

CMyWindow::CMyWindow(QWidget *parent) : QWidget(parent)
{
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
    m_textEdit = new QTextEdit(this);
    m_lineEdit = new QLineEdit(this);
    m_pushButton = new QPushButton(this);

    QGridLayout *gridlayout = new QGridLayout;
    
    //begin 頁面佈局
    m_pushButton->setText("Close");
    m_textEdit->setReadOnly(true);

    gridlayout->addWidget(m_textEdit, 0, 0, 5, 7);
    gridlayout->addWidget(m_lineEdit, 5, 0, 1, 5);
    gridlayout->addWidget(m_pushButton, 5, 5, 1, 2);
    this->setLayout(gridlayout);
    //end 頁面佈局
    
    m_filename = "./reg.txt";
    m_fstream.open(m_filename.string().c_str());

    stringstream strstream;
    strstream<<m_fstream.rdbuf();
    string str(strstream.str());
    m_textEdit->setPlainText(str.c_str());

    m_lineEdit->setFocus();
    this->setTabOrder(m_lineEdit, m_pushButton);

    connect(m_lineEdit, SIGNAL(textChanged(QString)), this, SLOT(highlightTextMatched(QString)));
    connect(m_pushButton, SIGNAL(clicked()), this, SLOT(close()));
}

void CMyWindow::highlightTextMatched(const QString &str)
{
    string wholewords = m_textEdit->toPlainText().toStdString();
    this->repaint();
    m_textEdit->setPlainText(m_textEdit->toPlainText().toStdString().c_str());

    if (str.toStdString().empty())
    {
        return;
    }

    cout<<str.toStdString().at(str.length() - 1)<<endl;

    string checkstr = str.toStdString();
    int little = 0;
    int middle = 0;
    for (unsigned int i = 0; i < checkstr.length(); i++)
    {
        if (checkstr[i] == '(')
        {
            if (i == 0 || (i > 0 && checkstr[i - 1] != '\\'))
            {
                little++;
            }
            else if (i > 0 && checkstr[i - 1] == '\\')
            {
            }
        }

        if (checkstr[i] == '[')
        {
            if (i == 0 || (i > 0 && checkstr[i - 1] != '\\'))
            {
                middle++;
            }
        }

        if (checkstr[i] == ')')
        {
            if (i == 0 || (i > 0 && checkstr[i - 1] != '\\'))
            {
                if (little == 0)
                {
                    return ;
                }
                little--;
            }
        }

        if (checkstr[i] == ']')
        {
            if (i == 0 || (i > 0 && checkstr[i - 1] != '\\'))
            {
                if (middle == 0)
                {
                    return ;
                }
                middle--;
            }
        }
    }

    if (little != 0 || middle != 0 || str.toStdString().at(str.length() - 1) == '\\')
    {
        return;
    }

    sregex regex = sregex::compile(str.toStdString(), icase);
    smatch match;

    try
    {
        regex_search(wholewords, match, regex);
        cout<<match[0]<<endl;
    }
    catch (regex_error &e)
    {
        cout<<e.what()<<endl;
        m_lineEdit->clear();
        return;
    }

    QString cQstr = ((string)match[0]).c_str();
    cout<<cQstr.toStdString()<<endl;

    QPalette palette = m_textEdit->palette();
    palette.setColor(QPalette::Highlight, palette.color(QPalette::Active, QPalette::Highlight));
    m_textEdit->setPalette(palette);

    m_textEdit->find(cQstr);
}

main.cpp : 

/******************************************************************************
 ** Coypright(C) 2014-2024 () technology Co., Ltd
 **
 ** 文件名 : test.cpp
 ** 版本號 : 1.0
 ** 描  述 : 
 ** 作  者 : cp3alai
 ** 日  期 : 2015.06.10
 ******************************************************************************/

#include "mywindow.h"

int main(int argc, char ** argv)
{
    QApplication app(argc, argv);
    QDesktopWidget *desk;
    CMyWindow *mywindow = new CMyWindow;

    mywindow->setWindowTitle(("正則練習器"));
    mywindow->resize(500, 500);
    mywindow->show();

    desk = QApplication::desktop();
    mywindow->move((desk->width() - mywindow->width())/2, (desk->height() - mywindow->height())/2);

    return app.exec();
}

使用方法:

在當前目錄下建立一個reg.txt的文件,然後隨便填一些內容即可加載.

效果如下:

可能代碼中還存在一些瑕疵,如果哪位同學發現了,還望指教.謝謝!!!




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章