?? 匯編版正則表達(dá)式.txt
字號(hào):
匯編版正則表達(dá)式 作者:AoGo 于2008-1-17上傳
--------------------------------------------------------------------------------
本文相關(guān)的例子:下載>>>
我們今天要學(xué)習(xí)的這個(gè)正則表達(dá)式庫,是我使用匯編語言編寫的一個(gè)表達(dá)式庫,它是以 EditPlus的表達(dá)式功能為參照并增強(qiáng)一些符號(hào)而編寫的,目前已經(jīng)開源,如果有需要可以參考一下代碼改進(jìn)一下。
首先,你要下載這個(gè)庫:http://www.aogosoft.com/download/explib.rar
或者,源代碼包含例子:http://www.aogosoft.com/sample/Src_Express.rar
如果你是使用MASMPlus,那就不需要再下載, MASMPlus中已經(jīng)帶有這個(gè)庫,不過因?yàn)闆]有例子程序,還是推薦從上面的鏈接中下載完整的包含例子的版本。
與通用而強(qiáng)大的正則表達(dá)式庫相比,這個(gè)庫優(yōu)點(diǎn):
1. 體積小,以庫文件方式發(fā)布,引用到程序中只占用1 - 2K的大小;
2. 功能強(qiáng),因?yàn)闆]有預(yù)處理與編譯,不需要占用內(nèi)存;
3. 把查找目標(biāo)當(dāng)成一行處理因而使用簡(jiǎn)單。
缺點(diǎn)是:
1. 復(fù)雜的表達(dá)式查找性能比其它表達(dá)式庫低;
2. 個(gè)別特定的復(fù)雜表達(dá)式查找無法實(shí)現(xiàn),如查找指定數(shù)目的某個(gè)表達(dá)式
另外,目前的這個(gè)表達(dá)式庫中有一個(gè)Bug,符號(hào)*在搜索時(shí),如果有結(jié)束條件,但是第一個(gè)字符就是結(jié)束條件時(shí),*會(huì)首先匹配前綴,如:
在字符串”abc”中搜索”%*[a]
正確的結(jié)果應(yīng)該是沒有匹配,上面的表達(dá)式意思是:在目標(biāo)中查找單詞字符,直到碰到字符a,并不把a(bǔ)放入匹配范圍。因?yàn)閎ug,上面的表達(dá)式首先判斷了a,再去判斷下一個(gè)字符的結(jié)束條件。結(jié)果是這個(gè)表達(dá)式與”%+[a]”的結(jié)果是一樣的了。這種情況只發(fā)生在第一個(gè)字符就是表達(dá)式結(jié)束條件的時(shí)候。
同時(shí),為了能夠讓使用者熟悉與方便使用,這個(gè)庫中加了很多影響性能的代碼,如果表達(dá)式有錯(cuò),庫函數(shù)會(huì)返回詳細(xì)出錯(cuò)的位置,這就意味著在分析表達(dá)式并查找時(shí),需要對(duì)可能出錯(cuò)的表達(dá)式符號(hào)進(jìn)行檢查,從而影響性能,下一版本的表達(dá)式庫,會(huì)包含兩個(gè)版本的搜索函數(shù),一個(gè)是學(xué)習(xí)用,一個(gè)是去掉了檢查代碼的實(shí)用函數(shù)。同時(shí)會(huì)修正上面所說的Bug。
這個(gè)庫中只有一個(gè)函數(shù),就是表達(dá)式搜索:
ExpressSearch:
lpCharTable ;字符表,一個(gè)字符是單詞還是字詞分隔符,由這個(gè)表來定義
;0表示使用默認(rèn)值
lpStart ;查找目標(biāo)的開始地址
lpEnd ;目標(biāo)的結(jié)束地址
lpExpress ;表達(dá)式的地址
lpOut ;輸出結(jié)果的數(shù)組字址
lpiCount ;數(shù)組大小與返回結(jié)果的數(shù)量
EF_* ;查找的方法標(biāo)志
lpCharTable,指向一個(gè)字符表,內(nèi)部默認(rèn)的字符表已經(jīng)輸出為Public,可以在程序中直接使用: Extrn DefCharTable :DWORD來引用,它是一個(gè)256個(gè)DWORD的數(shù)組,直接修改即可,或復(fù)制一份,再使用ExpressSearch時(shí),把地址傳給這個(gè)參數(shù),修改時(shí),首先參照以下標(biāo)志:
CF_WORD equ 1h ;單詞
CF_NUMBER equ 2h ;數(shù)字
CF_HEX equ 4h ;十六進(jìn)制
CF_BIN equ 8h ;二進(jìn)制
CF_UPCHAR equ 10h ;大寫字符
CF_LOWCHAR equ 20h ;小寫字符
CF_COMMENT equ 40h ;注釋字符
CF_COMMENTEND equ 80h ;注釋第二個(gè)字符
CF_TAB equ 100h ;語法線對(duì)齊符
CF_SPACE equ 200h ;空格
CF_ENTER equ 400h ;回車
CF_WARP equ 800h ;換行符
CF_MATCH equ 1000h ;包含符,如雙引號(hào)
CF_SELFMATCH equ 2000h ;包含符,如單引號(hào)
CF_INVALID equ 40000000h ;無效/無意義字符字符
CF_DOUBLEBYTE equ 80000000h ;中文字符首
比如,你要把符號(hào)&當(dāng)成一個(gè)字符,可以這樣:
or dword ptr DefCharTable[‘&’*4],CF_WORD
如果要把符號(hào)@當(dāng)成字詞分隔符,這樣:
and dword ptr DefCharTable[‘&’*4],not CF_WORD
修改之后,表達(dá)式搜索會(huì)立即使用新的標(biāo)志進(jìn)行判斷。如果復(fù)制了多份,可以針對(duì)不同的查找定義不同的字符表,而不需要苦惱,復(fù)制可直接申請(qǐng)內(nèi)存并復(fù)制:
invoke LocalAlloc,LMEM_FIXED,256
mov lpCharTable,eax
invoke RtlMoveMemory,eax,offset DefCharTable,256
同時(shí),表達(dá)式只使用到了很少的這些標(biāo)志,其它的標(biāo)志,是提供給用戶使用的,比如,搜索返回一個(gè)結(jié)果,如果要判斷它們是否是數(shù)字,只需依次判斷:
lea esi,結(jié)果字符串
movzx eax,byte ptr [esi]
.if dword ptr DefCharTable[eax*4] & CF_ NUMBER
;是數(shù)字字符
.endif
參數(shù)EF_*
是指定表達(dá)式搜索行為的一些標(biāo)志控制位,如下:
EF_DEC 表示從后往前搜索,此時(shí),lpStart與lpEnd是相反的,同時(shí),向前搜索時(shí),中文字符將無法正確識(shí)別,請(qǐng)一定注意。
EF_USEEXPRESS 使用表達(dá)式,如果沒有些標(biāo)志,將使用普通的搜索方法,這樣速度是很快的,因?yàn)檫@個(gè)表達(dá)式搜索庫中有專門針對(duì)普通搜索的函數(shù),速度當(dāng)然比表達(dá)式快,所以如果只是普通搜索,請(qǐng)不要包含此標(biāo)志。
EF_WORDCASE 默認(rèn)不區(qū)分大小寫,包含此標(biāo)志,將區(qū)分大小寫。
EF_MATCHWORD 匹配整個(gè)表達(dá)式,也就是結(jié)果范圍的字串,最前一個(gè)字符與最后一個(gè)字符與相鄰的字符必須不是相同字符表定義的字符。
EF_BEGINNOTLINEBEGIN 開始位置不是行首,如果是從一個(gè)結(jié)果中再搜索,目標(biāo)首是緊跟著上一次搜索內(nèi)存地址,可包含此標(biāo)志,表示第一個(gè)字符位置不是行首。否則會(huì)當(dāng)成行首對(duì)待。另外,表達(dá)式搜索函數(shù)庫,行首行尾是以0D0A定義的,如果搜索目標(biāo)中包含0D或0A,會(huì)當(dāng)成行尾與行首對(duì)待。
EF_ENDNOTLINEEND 結(jié)束位置不是行尾,同上。
EF_ENDISSIZE 表示lpEnd不是地址,而是查找目標(biāo)的長(zhǎng)度。
EF_FINDONCE 只查找一次,如在“abc”中查找”b”,包含此標(biāo)志時(shí)失敗,因?yàn)橹槐容^了一次,也就是a與b,就結(jié)束了。通常用于在結(jié)果中獲得特定位置的字符。
EF_MODIFLINESTARTEND 查找結(jié)束后,如果是以^開頭或$結(jié)束,將選擇0D與0A字符,包含此標(biāo)志,將自動(dòng)去掉這兩個(gè)字符。
EF_DOUBLEISWORD 中文字符也是單詞,包含此標(biāo)志,使用%號(hào)時(shí),會(huì)自動(dòng)匹配。
EF_RANGENOTCASE 表達(dá)式[]中總是區(qū)分大小寫,有些時(shí)候,整個(gè)表達(dá)式不需要區(qū)分大小寫,而[]中卻需要區(qū)分時(shí),包含此標(biāo)志。
表達(dá)式查找時(shí)有可能發(fā)生的錯(cuò)誤:
EFERR_NOTCONST 沒有常數(shù)定義
EFERR_EXPNOTSUPPORT 不能這樣使用符號(hào)
EFERR_NOTCLOSEBRACKET 沒有關(guān)閉括號(hào)
EFERR_EMPTYEXPRESS 空的表達(dá)式,()/[]/{}/<>
EFERR_NOTEXISTEXP 多余的表達(dá)式結(jié)束符,請(qǐng)使用\],\),\>等等
EFERR_NOTBYONSELF 表達(dá)式符號(hào)不能單獨(dú)使用
EFERR_NOTLOOPEND 對(duì)于?*/?+必須設(shè)置結(jié)束條件,同時(shí),*/+對(duì)于?來說是一樣的
EFERR_DEADLOOP 在使用*/+的表達(dá)式里面的整個(gè)表達(dá)式均是可忽略的,如(.*)+,因?yàn)?*總是成功
后面的+要求成功時(shí)繼續(xù),這是一個(gè)死循環(huán).
EFERR_INVALIDEXP 無效表達(dá)式,如整個(gè)表達(dá)式就是 %*,因?yàn)?是可忽略符號(hào),則上述表達(dá)式總是成功
下面,我們開始使用表達(dá)式搜索函數(shù),表達(dá)式符號(hào)如下:
? 一個(gè)任意字符
. 一個(gè)空格或制表符
, 一個(gè)字詞分隔符(包含.)
% 一個(gè)單詞字符,字符是否是一個(gè)單詞以字符表來定義
*<>|[] 0或更多,如果有結(jié)束條件,是直到[結(jié)束條件],如:?*<=>,直到碰到=號(hào)
+<>|[] 1或更多,如果有結(jié)束條件,是直到[結(jié)束條件],如:?+<=>,直到碰到=號(hào)
# 轉(zhuǎn)義符,后面跟十六進(jìn)制數(shù),如#0D表達(dá)回車符號(hào)。#?表示中文字符
\ 字符,中間的字符是實(shí)際符號(hào) 如.表示空格制表符\.表示一個(gè)"."
[-] 在范圍內(nèi) [a-b],或者清單,[abcdef],表達(dá)式符號(hào)仍然使用\來轉(zhuǎn)換,如()/<>/{}/[]
" " " "內(nèi)包含的必須完全一樣,不區(qū)分大小寫,不會(huì)理會(huì)是否包含EF_WORDCASE
' ' ' '與" " 的區(qū)別在于' '區(qū)分大小寫,不會(huì)理會(huì)是否包含EF_WORDCASE
( ) 表達(dá)式,可嵌套,嵌套層次數(shù)無限制
{ } 標(biāo)記并返回{}所包含的區(qū)域,可用在任何表達(dá)式內(nèi).
| 或者,支持任意表達(dá)式成員組合,如:(.)|(a)|((.*)|(%+))
!() 條件取反,取反條件必須使用表達(dá)式包含
^ 行首
$ 行尾
我們來從例子進(jìn)行分析:
;MASMPlus 代碼模板
.386
.Model Flat, StdCall
Option Casemap :None
Include windows.inc
Include user32.inc
Include kernel32.inc
Include gdi32.inc
include express.inc ;MASMPlus已經(jīng)自帶了這個(gè)表達(dá)式庫。可以直接使用
includelib express.lib ;引用庫文件
includelib gdi32.lib
IncludeLib user32.lib
IncludeLib kernel32.lib
include macro.asm
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -