⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 汇编版正则表达式.txt

📁 会变语言实现的一些程序
💻 TXT
📖 第 1 页 / 共 2 页
字号:
汇编版正则表达式  作者:AoGo 于2008-1-17上传

--------------------------------------------------------------------------------
     本文相关的例子:下载>>> 
    我们今天要学习的这个正则表达式库,是我使用汇编语言编写的一个表达式库,它是以 EditPlus的表达式功能为参照并增强一些符号而编写的,目前已经开源,如果有需要可以参考一下代码改进一下。
    首先,你要下载这个库:http://www.aogosoft.com/download/explib.rar
    或者,源代码包含例子:http://www.aogosoft.com/sample/Src_Express.rar

    如果你是使用MASMPlus,那就不需要再下载, MASMPlus中已经带有这个库,不过因为没有例子程序,还是推荐从上面的链接中下载完整的包含例子的版本。
与通用而强大的正则表达式库相比,这个库优点:
    1.     体积小,以库文件方式发布,引用到程序中只占用1 - 2K的大小;
    2.     功能强,因为没有预处理与编译,不需要占用内存;
    3.     把查找目标当成一行处理因而使用简单。
缺点是:
    1.     复杂的表达式查找性能比其它表达式库低;
    2.     个别特定的复杂表达式查找无法实现,如查找指定数目的某个表达式

    另外,目前的这个表达式库中有一个Bug,符号*在搜索时,如果有结束条件,但是第一个字符就是结束条件时,*会首先匹配前缀,如:
    在字符串”abc”中搜索”%*[a]

    正确的结果应该是没有匹配,上面的表达式意思是:在目标中查找单词字符,直到碰到字符a,并不把a放入匹配范围。因为bug,上面的表达式首先判断了a,再去判断下一个字符的结束条件。结果是这个表达式与”%+[a]”的结果是一样的了。这种情况只发生在第一个字符就是表达式结束条件的时候。
    同时,为了能够让使用者熟悉与方便使用,这个库中加了很多影响性能的代码,如果表达式有错,库函数会返回详细出错的位置,这就意味着在分析表达式并查找时,需要对可能出错的表达式符号进行检查,从而影响性能,下一版本的表达式库,会包含两个版本的搜索函数,一个是学习用,一个是去掉了检查代码的实用函数。同时会修正上面所说的Bug。

    这个库中只有一个函数,就是表达式搜索:

ExpressSearch:
    lpCharTable    ;字符表,一个字符是单词还是字词分隔符,由这个表来定义
                ;0表示使用默认值
    lpStart        ;查找目标的开始地址
    lpEnd        ;目标的结束地址
    lpExpress        ;表达式的地址
    lpOut        ;输出结果的数组字址
    lpiCount        ;数组大小与返回结果的数量
    EF_*        ;查找的方法标志 

lpCharTable,指向一个字符表,内部默认的字符表已经输出为Public,可以在程序中直接使用: Extrn DefCharTable :DWORD来引用,它是一个256个DWORD的数组,直接修改即可,或复制一份,再使用ExpressSearch时,把地址传给这个参数,修改时,首先参照以下标志:

CF_WORD equ 1h        ;单词
CF_NUMBER equ 2h        ;数字
CF_HEX    equ 4h        ;十六进制
CF_BIN equ 8h        ;二进制
CF_UPCHAR equ 10h        ;大写字符
CF_LOWCHAR equ 20h        ;小写字符
CF_COMMENT equ 40h        ;注释字符
CF_COMMENTEND equ 80h        ;注释第二个字符
CF_TAB equ 100h        ;语法线对齐符
CF_SPACE equ 200h        ;空格
CF_ENTER equ 400h        ;回车
CF_WARP equ 800h        ;换行符
CF_MATCH equ 1000h        ;包含符,如双引号
CF_SELFMATCH    equ 2000h        ;包含符,如单引号
CF_INVALID    equ 40000000h        ;无效/无意义字符字符
CF_DOUBLEBYTE equ 80000000h        ;中文字符首 


    比如,你要把符号&当成一个字符,可以这样:
    or dword ptr DefCharTable[‘&’*4],CF_WORD

    如果要把符号@当成字词分隔符,这样:
   and dword ptr DefCharTable[‘&’*4],not CF_WORD

    修改之后,表达式搜索会立即使用新的标志进行判断。如果复制了多份,可以针对不同的查找定义不同的字符表,而不需要苦恼,复制可直接申请内存并复制:

invoke LocalAlloc,LMEM_FIXED,256
mov lpCharTable,eax
invoke RtlMoveMemory,eax,offset DefCharTable,256 

    同时,表达式只使用到了很少的这些标志,其它的标志,是提供给用户使用的,比如,搜索返回一个结果,如果要判断它们是否是数字,只需依次判断:


lea esi,结果字符串
movzx eax,byte ptr [esi]
.if dword ptr DefCharTable[eax*4] & CF_ NUMBER
    ;是数字字符
.endif 

参数EF_*
    是指定表达式搜索行为的一些标志控制位,如下:

EF_DEC 表示从后往前搜索,此时,lpStart与lpEnd是相反的,同时,向前搜索时,中文字符将无法正确识别,请一定注意。 
EF_USEEXPRESS 使用表达式,如果没有些标志,将使用普通的搜索方法,这样速度是很快的,因为这个表达式搜索库中有专门针对普通搜索的函数,速度当然比表达式快,所以如果只是普通搜索,请不要包含此标志。 
EF_WORDCASE 默认不区分大小写,包含此标志,将区分大小写。 
EF_MATCHWORD 匹配整个表达式,也就是结果范围的字串,最前一个字符与最后一个字符与相邻的字符必须不是相同字符表定义的字符。 
EF_BEGINNOTLINEBEGIN 开始位置不是行首,如果是从一个结果中再搜索,目标首是紧跟着上一次搜索内存地址,可包含此标志,表示第一个字符位置不是行首。否则会当成行首对待。另外,表达式搜索函数库,行首行尾是以0D0A定义的,如果搜索目标中包含0D或0A,会当成行尾与行首对待。 
EF_ENDNOTLINEEND 结束位置不是行尾,同上。 
EF_ENDISSIZE 表示lpEnd不是地址,而是查找目标的长度。 
EF_FINDONCE 只查找一次,如在“abc”中查找”b”,包含此标志时失败,因为只比较了一次,也就是a与b,就结束了。通常用于在结果中获得特定位置的字符。 
EF_MODIFLINESTARTEND 查找结束后,如果是以^开头或$结束,将选择0D与0A字符,包含此标志,将自动去掉这两个字符。 
EF_DOUBLEISWORD 中文字符也是单词,包含此标志,使用%号时,会自动匹配。 
EF_RANGENOTCASE 表达式[]中总是区分大小写,有些时候,整个表达式不需要区分大小写,而[]中却需要区分时,包含此标志。 

表达式查找时有可能发生的错误:


EFERR_NOTCONST 没有常数定义 
EFERR_EXPNOTSUPPORT 不能这样使用符号 
EFERR_NOTCLOSEBRACKET 没有关闭括号 
EFERR_EMPTYEXPRESS 空的表达式,()/[]/{}/<> 
EFERR_NOTEXISTEXP 多余的表达式结束符,请使用\],\),\>等等 
EFERR_NOTBYONSELF 表达式符号不能单独使用 
EFERR_NOTLOOPEND 对于?*/?+必须设置结束条件,同时,*/+对于?来说是一样的 
EFERR_DEADLOOP 在使用*/+的表达式里面的整个表达式均是可忽略的,如(.*)+,因为.*总是成功
后面的+要求成功时继续,这是一个死循环. 
EFERR_INVALIDEXP 无效表达式,如整个表达式就是 %*,因为*是可忽略符号,则上述表达式总是成功 

下面,我们开始使用表达式搜索函数,表达式符号如下:

? 一个任意字符 
. 一个空格或制表符 
, 一个字词分隔符(包含.) 
% 一个单词字符,字符是否是一个单词以字符表来定义 
*<>|[] 0或更多,如果有结束条件,是直到[结束条件],如:?*<=>,直到碰到=号 
+<>|[] 1或更多,如果有结束条件,是直到[结束条件],如:?+<=>,直到碰到=号 
# 转义符,后面跟十六进制数,如#0D表达回车符号。#?表示中文字符 
\ 字符,中间的字符是实际符号 如.表示空格制表符\.表示一个"." 
[-] 在范围内 [a-b],或者清单,[abcdef],表达式符号仍然使用\来转换,如()/<>/{}/[] 
" " " "内包含的必须完全一样,不区分大小写,不会理会是否包含EF_WORDCASE 
' ' ' '与" " 的区别在于' '区分大小写,不会理会是否包含EF_WORDCASE 
( ) 表达式,可嵌套,嵌套层次数无限制 
{ } 标记并返回{}所包含的区域,可用在任何表达式内. 
| 或者,支持任意表达式成员组合,如:(.)|(a)|((.*)|(%+)) 
!() 条件取反,取反条件必须使用表达式包含 
^ 行首 
$ 行尾 

我们来从例子进行分析:

;MASMPlus 代码模板 
.386
.Model Flat, StdCall
Option Casemap :None

Include windows.inc
Include user32.inc
Include kernel32.inc
Include gdi32.inc
include express.inc             ;MASMPlus已经自带了这个表达式库。可以直接使用

includelib express.lib        ;引用库文件
includelib gdi32.lib
IncludeLib user32.lib
IncludeLib kernel32.lib
include macro.asm
    

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -