首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

VC6下Greta正則表達式庫整合與實戰應用指南

     編輯:關於VC++

正則表達式是文本處理利器,但手寫解析器效率低、維護難。Greta 是輕量級 C++ 正則庫(僅 6 個檔案),支援 Perl 兼容語法、STL 介面、VC6 友好。本文記錄 Greta 在 VC6 MFC 專案中的整合步驟、核心類別用法、匹配/替換/分割三大功能完整測試代碼,並解決 VC6 專有編譯陷阱。

為什麼選擇 Greta?

VC6 專案整合步驟

1. 獲取源碼

官網:greta,下載 greta.zip 解壓取 6 個檔案:

  • regexpr.h, regexpr2.h(主頭檔)
  • regexpr.cpp, regexpr2.cpp
  • char_traits.h, traits.h

2. 專案配置

  1. 將 6 檔複製到專案目錄 greta\ 子資料夾
  2. 專案加入現有項目:全部 6 檔
  3. 關鍵:在 regexpr.cpp 和 regexpr2.cpp 頂部加入:
    #include "stdafx.h" (預編譯頭,否則報錯)
  4. 若仍報錯(約 11 個 C2xxx 錯誤),嘗試:
    Project → Settings → C/C++ → Code Generation → Use MFC in a Static Library

3. 程式碼引用


#include 
#include "greta/regexpr2.h" // 單一頭檔足夠

using namespace std;
using namespace regex; // Greta 命名空間

核心類別與功能

庫體積VC6支援學習曲線特點
Boost.Regex巨大需獨立編譯陡峭功能最全、標準準則
CAtlRegExp (ATL)中等VC7+中等ATL 專用、語法受限
Greta6檔原生支援平緩Perl語法、STL風格、單頭檔可用

常用旗標

  • GLOBAL:全域匹配(非首次)
  • ALLBACKREFS:捕獲所有反向引用
  • NOCASE:忽略大小寫
  • MULTILINE:多行模式 ^$ 匹配行首尾
  • SINGLELINE:單行模式 . 匹配換行

完整測試程式:MFC 對話框應用

介面配置

  • 編輯框:m_strReg(正則)、m_strSource(源文本)、m_strSub(替換文本)、m_strResult(結果)
  • 核取方塊:m_bCase(忽略大小寫)、m_bMulti(多行)、m_bSingle(單行)
  • 按鍵觸發:F5=匹配、F6=替換、F7=分割

核心實現代碼


void CRegTestDlg::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
    if (nChar == VK_ESCAPE) { CDialog::OnOK(); return; }
    
    UpdateData(TRUE);
    
    // 旗標組合
    REGEX_FLAGS dw = GLOBAL | ALLBACKREFS;
    if (m_bCase) dw |= NOCASE;
    if (m_bMulti) dw |= MULTILINE;
    if (m_bSingle) dw |= SINGLELINE;
    
    rpattern pat((LPCTSTR)m_strReg, dw);
    int nGroups = pat.cgroups(); // 捕獲組數
    
    if (nChar == VK_F5) { // === 匹配查找 ===
        m_strResult = _T("");
        match_results result;
        double tmS = clock();
        
        match_results::backref_type br = pat.match((LPCTSTR)m_strSource, result);
        int nCount = 0;
        
        if (br.matched) {
            // 遍歷方式 1:all_backrefs() 向量
            match_results::backref_vector vec = result.all_backrefs();
            for (auto it = vec.begin(); it != vec.end(); ++it) {
                nCount++;
                m_strResult += it->str().c_str();
                m_strResult += _T("\r\n---------------------------------------------\r\n");
            }
            
            // 遍歷方式 2:索引訪問(按組分組)
            for (int i = 0; i < result.cbackrefs(); i++) {
                if (i % nGroups == 0) { // 每組第一個為整體匹配
                    nCount++;
                    m_strResult += result.backref(i).str().c_str();
                    m_strResult += _T("\r\n---------------------------------------------\r\n");
                }
            }
        }
        
        double tmE = clock();
        CString tip; tip.Format(_T("耗時 %.2f ms, 匹配 %d 處"), tmE - tmS, nCount);
        GetDlgItem(IDC_STATIC_TIP)->SetWindowText(tip);
        UpdateData(FALSE);
    }
    else if (nChar == VK_F6) { // === 替換 ===
        m_strResult = _T("");
        double tmS = clock();
        
        rpattern pat2((LPCTSTR)m_strReg, (LPCTSTR)m_strSub, dw);
        subst_results subResult;
        string str((LPCTSTR)m_strSource);
        
        int nCount = pat2.substitute(str, subResult);
        m_strResult = str.c_str();
        
        double tmE = clock();
        CString tip; tip.Format(_T("耗時 %.2f ms, 替換 %d 處"), tmE - tmS, nCount);
        GetDlgItem(IDC_STATIC_TIP)->SetWindowText(tip);
        UpdateData(FALSE);
    }
    else if (nChar == VK_F7) { // === 分割 ===
        m_strResult = _T("");
        double tmS = clock();
        
        rpattern pat3((LPCTSTR)m_strReg, dw);
        split_results splitResult;
        string str((LPCTSTR)m_strSource);
        
        int nCount = pat3.split(str, splitResult);
        for (int i = 0; i < nCount; i++) {
            m_strResult += splitResult[i].c_str();
            m_strResult += _T("\r\n---------------------------------------------\r\n");
        }
        
        double tmE = clock();
        CString tip; tip.Format(_T("耗時 %.2f ms, 分割 %d 段"), tmE - tmS, nCount);
        GetDlgItem(IDC_STATIC_TIP)->SetWindowText(tip);
        UpdateData(FALSE);
    }
    
    CDialog::OnKeyDown(nChar, nRepCnt, nFlags);
}

測試程式介面

Greta 測試工具運行截圖

常用正則範例速查

類別功能關鍵方法
rpattern正則模式編譯、旗標設定match(), substitute(), split(), cgroups()
match_results匹配結果容器all_backrefs(), backref(i), cbackrefs(), matched
subst_results替換結果輸出字串、替換次數
split_results分割結果operator[], size()

VC6 常見編譯錯誤與對策

需求正則說明
Email\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*標準郵箱格式
手機號(大陸)1[3-9]\d{9}11位、1開頭
IPv4((25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(25[0-5]|2[0-4]\d|[01]?\d?\d)四段 0-255
中文[\u4e00-\u9fa5]+Unicode 範圍
HTML標籤<[^>]+>貪婪匹配
日期 YYYY-MM-DD\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])簡易驗證
錯誤現象原因解決
C1010: unexpected end of file while looking for precompiled header.cpp 未含 stdafx.h在 regexpr.cpp/regexpr2.cpp 首行加 #include "stdafx.h"
C2xxx: 樣板/命名空間相關錯誤VC6 樣板支援不全設定 MFC 靜態連結,或升級 VC6 SP6
LNK2001: 未解析外部符號.cpp 未加入專案專案右鍵 Add Files 選中 regexpr.cpp regexpr2.cpp
運行時 Access Violation正則語法錯誤導致內部崩潰用 try-catch 包裹 pat.match(),輸入前驗證

效能與替代方案

  • Greta 基於回溯 NFA,極端情況(如 (a+)+b 匹配 aaaaac)可能指數級回溯
  • 高效能場景建議:RE2(Google,DFA保證線性時間)、PCRE2(JIT編譯)、std::regex(C++11,VC10+)
  • 輕量嵌入式:tiny-regex-c(單檔、無依賴、功能受限)

總結

Greta 以 極小體積、Perl相容語法、STL風格介面 成為 VC6 專案引入正則的最佳選擇。本文提供的測試工具可作為專案整合驗收標準,三大核心功能(匹配/替換/分割)代碼可直接遷移至實際業務模組。建議配合《正則表達式30分鐘入門》快速掌握語法,實戰中善用 GLOBAL|ALLBACKREFS 旗標獲取完整捕獲組資訊。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved