文本字符串的處理、分析一直是寫程序中不可避免的問題,長時間以來,自己對正則表達式這個紙老虎一直退避三捨。也許是懶的緣故吧,一般遇到字符串處理問題的時候,都是自己寫個小程序完事,但工作效率實在是低下,做的多了就有點煩--都是重復性工作。昨天閒著沒事,終於下決心看看正則了,很欣喜,收獲還是不小的。
關於正則表達式的學習,推薦這篇文章,“正則表達式三十分鐘入門”,我這麼零基礎的人,邊看邊練,兩個小時確實是入門了,所以強烈推薦。其他關於正則的詳細內容就不說了,不屬於本文討論的內容,下面言歸正傳。
學正則表達式,練習是少不了的,雖然工具不少,但為了以後自己寫程序時方便,還是決定自己寫一個。Google了一下,正則庫還真是不少,像Boost、CAtlReg、Greta等,還有其他很多。粗粗看了一下,覺得Boost塊頭太大了,還得一步步編譯啥的,懶人就放棄了,CAtlreg又好像不能在VC6下用,看看Greta就6個文件--著實很親切,所以就它了。
網上關於Greta的文檔不是很多,不知道是太簡單了還是用的人太少,例子大多也是greta庫文件裡的示例,太簡單,沒有詳細的匹配、替換、分割功能的用法。
本文測試的環境是VC6(sp6)MFC環境,步驟如下,
1)直接將greta六個源文件拷貝到工程目錄下,為了方便,建了個greta目錄;
這裡測試就直接用了源文件,其實還可以先把greta編譯成庫文件來使用,更推薦這種用法。
2)包含greta頭文件;
#include <string>
#include "greta\regexpr2.h"//這一個就夠了
using namespace std;
using namespace regex;//greta庫的命名空間
3)在greta兩個cpp文件中加上頭文件"stdafx.h",否則會報錯;
另外,如果仍遇到11個左右的莫名其妙錯誤時,可以把MFC設置為靜態鏈接模式,我剛開始時候就遇到了這個問題,搞了半天不知道什麼原因,後來就改了靜態選項;不過寫本文時,本來想看看這個錯誤是什麼,好給大家貼出來,把MFC改回共享鏈接又正常了...那些錯誤就是搞不出來(bt...)
4)環境設置好,下面就可以使用了;
幾個重要的對象:
rpattern--正則模式及設置,主要就用它;
match_results--匹配結果容器;
subst_results--替換結果容器;
split_results--分割結果容器;
基本主要的就這幾個了,具體用法,貼代碼,大家自己看;
////////////////////////////////// if( nChar==VK_ESCAPE ) CDialog::OnOK(); else if( nChar==VK_F5 ) //匹配查找 { UpdateData(); m_strResult = ""; match_results result; REGEX_FLAGS dw = GLOBAL | ALLBACKREFS; if( m_bCase ) dw |= NOCASE; if( m_bMulti ) dw |= MULTILINE; if( m_bSingle ) dw |= SINGLELINE; // double tmS = clock(); // rpattern pat((LPCTSTR)m_strReg, dw); int iGroups = pat.cgroups(); int nCount = 0; match_results::backref_type br = pat.match( (LPCTSTR)m_strSource, result ); if( 0 )//遍歷結果方式1,任選一種方式即可 { match_results::backref_vector vec = result.all_backrefs(); match_results::backref_vector::iterator iter; if( br.matched ) { for( iter = vec.begin(); iter != vec.end(); iter++ ) { nCount++; string str = (*iter).str(); m_strResult += str.c_str(); m_strResult += "\r\n---------------------------------------------\r\n"; } } } if( 1 )//遍歷結果方式2 { if( br.matched ) { for( int i=0;i<result.cbackrefs();i++ ) { if( i%iGroups == 0 ) { nCount++; m_strResult += result.backref(i).str().c_str(); m_strResult += "\r\n---------------------------------------------\r\n"; } } } } double tmE = clock(); CString strTip; strTip.Format(_T(" 運行時間 %.2fms, 共找到 %d個匹配;"), double(tmE-tmS), nCount); GetDlgItem(IDC_STATIC_TIP)->SetWindowText(strTip); // UpdateData(FALSE); } else if( nChar == VK_F6 )//替換 { UpdateData(); m_strResult = ""; // REGEX_FLAGS dw = GLOBAL | ALLBACKREFS; if( m_bCase ) dw |= NOCASE; if( m_bMulti ) dw |= MULTILINE; if( m_bSingle ) dw |= SINGLELINE; double tmS = clock(); // rpattern pat((LPCTSTR)m_strReg, (LPCTSTR)m_strSub, dw); subst_results subResult; // string str((LPCTSTR)m_strSource); int nCount = pat.substitute(str, subResult); m_strResult = str.c_str(); // double tmE = clock(); CString strTip; strTip.Format(_T(" 運行時間 %.2fms, 共完成替換 %d處;"), double(tmE-tmS), nCount); GetDlgItem(IDC_STATIC_TIP)->SetWindowText(strTip); // UpdateData(FALSE); } else if( nChar == VK_F7 )//分割字符串 { UpdateData(); m_strResult = ""; // REGEX_FLAGS dw = GLOBAL | ALLBACKREFS; if( m_bCase ) dw |= NOCASE; if( m_bMulti ) dw |= MULTILINE; if( m_bSingle ) dw |= SINGLELINE; double tmS = clock(); // rpattern pat((LPCTSTR)m_strReg, dw); split_results splitResult; // string str((LPCTSTR)m_strSource); int nCount = pat.split(str, splitResult); for( int ni=0;ni<nCount;ni++ ) { string strSplit = splitResult[ni]; m_strResult += strSplit.c_str(); m_strResult += "\r\n---------------------------------------------\r\n"; } // double tmE = clock(); CString strTip; strTip.Format(_T(" 運行時間 %.2fms, 共找到 %d個匹配;"), double(tmE-tmS), nCount); GetDlgItem(IDC_STATIC_TIP)->SetWindowText(strTip); // UpdateData(FALSE); } /////----------結束-----------////////
以上為初步測試結果,可能在使用和介紹中有錯誤和不當之初,歡迎大家多交流探討。
本文配套源碼