




已阅读5页,还剩12页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
DB2中实现正则表达式(1) 2005-12-01 10:00 出处:IBM中国 【导读】本文简略地介绍了正则表达式以及 DB2 中可用的字符串比较和匹配功能。还描述了为什么正则表达式的强大功能是如此有用。 正则表达式正则表达式用于查找和替换字符串中的模式。正则表达式是用某种语法定义的,正则表达式引擎采用这种语法并将它与字符串进行比较。引擎返回字符串是否与语法匹配的指示;也即,该字符串是否包含能够从该语法派生的子串。此外,引擎还能够返回匹配的子串。术语“模式(pattern)”用来表示语法。 最基本的模式仅由单个字母组成。当与该模式进行比较时,包含这个字母的字符串就是一个“匹配”。例如,如果模式是“a”,则字符串“abcd”就是一个匹配,而字符串“xyz”则不是。正则表达式的强大功能来自于预定义的运算符(也称为元字符),它们可以用很小的空间来表示模式。根据“方言”和受支持的功能,可以使用不同的元字符。通常,其中的一些可用字符如下:| 二中择一 分组* 多次出现(也匹配零次出现)+ 多次出现(至少一次)? 随意的出现次数 反斜杠 不同的系统实现了常用正则表达式的各种扩展。编程语言 Perl 中使用的正则表达式支持进一步的缩写。本文中所用的库实现了这些扩展。下面摘录了其中部分可以在 Perl 正则表达式语言中使用的缩写:s 任意空白字符w 任意字母数字字符d 任意数字字符 另一个更高级的示例是模式“A-Z* = (0-9|0x00);”。与这个模式相匹配的字符串包含这样的子串:它由几个大写字母、后面跟上一个空格、一个等号、另一个空格,然后是一个数字或字符串“0x00”组成。该子串的最后一个字符必须是分号。使用 Perl,这个模式可以表示为“w* = (d|0x00);”。“NM = 0x00;”和“X = 7;”是两个可以与该模式匹配的字符串。但字符串“Z = 123;”不能匹配,因为 123 是由三个数字所组成的。DB2 中的字符串匹配除了 Extender 以外,DB2 还允许几种用于文本比较的函数和运算符。但那些函数和运算符要么在用于模式匹配的功能方面有限制,要么就是会给可能使用它们的查询带来复杂性。这里简要地摘录几个可用的功能:= 或 谓词:逐字符地比较两个字符串是否相等。 LIKE 谓词:使用通配符的基本模式匹配。 LOCATE 函数:在字符串中查找子串。 尽管也可以用 SQL 运算符表示模式“A-Z* = (0-9|0x00);”,但那样会很麻烦。例如,下列 SELECT 语句的 WHERE 子句中所使用的谓词会匹配字符串“str”中等号之后的部分,如 清单 1所示: 清单 1. 使用 LIKE 匹配模式 SELECT strFROM strTableWHERE ( str LIKE % = 0;% OR str LIKE % = 1;% OR str LIKE % = 2;% OR str LIKE % = 3;% OR str LIKE % = 4;% OR str LIKE % = 5;% OR str LIKE % = 7;% OR str LIKE % = 7;% OR str LIKE % = 8;% OR str LIKE % = 9;% OR str LIKE % = 0x00;% ) 这增加了可以匹配“A-Z*”子模式的谓词的复杂度,这可以使用对整个字符串进行迭代并进行逐字符比较的函数来完成,但您会发现使用内置功能既冗长又复杂。示例方案让我们定义下列清单( 清单 2)并插入几行: 清单 2. 创建我们的样本表 CREATE TABLE strTable ( c1 INTEGER, str VARCHAR(500) );INSERT INTO strTable VALUES ( 1, some text; ), ( 2, variable = 1234; ), ( 3, var2 = string variable; ), ( 4, xyz = ), ( 5, myVar = 0x00; ), ( 6, # comment ), ( 7, abc = def ); 这个 清单及其数据被用于下面的所有示例。 SELECT * FROM strTable;C1 STR- - 1 some text; 2 variable = 1234; 3 var2 = string variable; 4 xyz = 5 myVar = 0x00; 6 # comment 7 abc = def 7 record(s) selected. 实现模式匹配函数您可以使用 DB2 的可扩展机制,在 SQL 语句内使用 UDF,以便显著地改善这种情形。通过定义名为 regex1 的 UDF(它采用模式和字符串作为输入参数), 清单 1中的 WHERE 子句现在可以写得象 清单 3中所示的那样: 清单 3. 使用 regex UDF 来简化模式匹配 SELECT strFROM strTableWHERE regex1(w* = (d|0x00);, str) = 1 在本示例中,使用带有 Perl 扩展的正则表达式来匹配完整的模式,而不仅仅是 清单 1中给出的 LIKE 谓词所对应的部分模式。正如您所看到的,使用函数来为该模式编写谓词比用 LIKE 谓词表示同样的语义要容易得多。 实现 UDF在我的示例实现中,我选择了现有的名为 PCRE(Perl 兼容的正则表达式,Perl-compatible regular expression)的模式匹配引擎。该引擎提供了用来处理模式和执行匹配的 C API。该引擎和查询中所用的 SQL 语言之间“缺失的部分”是 UDF。该 UDF 由两部分组成:在数据库中创建(或注册)该函数的 CREATE FUNCTION 语句。 该函数的主体,它实现了用于正则表达式匹配引擎的 C API 调用的封装器清单 4显示了用于创建该函数的 SQL 语句。 清单 4. 注册 regex1 函数 CREATE FUNCTION regex1(pattern VARCHAR(2048), string CLOB(10M) RETURNS INTEGER SPECIFIC regexSimple EXTERNAL NAME regexUdf!regexpSimple LANGUAGE C PARAMETER STYLE DB2SQL DETERMINISTIC NOT FENCED RETURNS NULL ON NULL INPUT NO SQL NO EXTERNAL ACTION ALLOW PARALLEL; 注:请参阅 DB2 SQL Reference以获取所有子句的详细含义。可以修改参数的长度以适应您的需求。我在此处展示某些值并没有任何推荐使用它们的用意。DB2中实现正则表达式(2) 2005-12-01 10:00 出处:IBM中国 【导读】本文简略地介绍了正则表达式以及 DB2 中可用的字符串比较和匹配功能。还描述了为什么正则表达式的强大功能是如此有用。 第二部分由一小段 C 代码组成,它实现了 UDF 入口点。在查询执行期间,DB2 为每个要与模式匹配的行调用这个入口点。 清单 5中的示例列出了该代码的清单。有关 pcre_* 函数和宏的描述,请参考 PCRE 库的文档。有关 C 代码的编译和共享库的构建,请参考 DB2 Application Development Guide。 清单 5. 实现 rege1x UDF 入口点的 C 代码 #include #include void regexpSimple( / input parameters SQLUDF_VARCHAR *pattern, SQLUDF_CLOB *str, / output SQLUDF_INTEGER *match, / null indicators SQLUDF_NULLIND *pattern_ind, SQLUDF_NULLIND *str_ind, SQLUDF_NULLIND *match_ind, SQLUDF_TRAIL_ARGS) pcre *re = NULL; const char *error = NULL; int errOffset = 0; int rc = 0; / we assume successful return *match_ind = 0; / compile the pattern to its internal representation re = pcre_compile(pattern, 0 /* default options */, &error, &errOffset, NULL); if (re = NULL) snprintf(SQLUDF_MSGTX, 70, Regexp compilation failed at offset %d: %sn, errOffset, error); strcpy(SQLUDF_STATE, 38900); (*pcre_free)(re); return; / match the string againts the pattern rc = pcre_exec(re, NULL, str-data, str-length, 0, 0 /* default options */, NULL, 0); switch (rc) case PCRE_ERROR_NOMATCH: *match = 0; break; case PCRE_ERROR_BADOPTION: snprintf(SQLUDF_MSGTX, 70, An unrecognized bit was set in the options argument); strcpy(SQLUDF_STATE, 38901); break; case PCRE_ERROR_NOMEMORY: snprintf(SQLUDF_MSGTX, 70, Not enough memory available.); strcpy(SQLUDF_STATE, 38902); break; default: if (rc data; *match_ind = 0; switch (SQLUDF_CALLT) case SQLUDF_FIRST_CALL: / initialize data on the scratchpad scratch-re = NULL; scratch-extra = NULL; scratch-error = NULL; scratch-errOffset = 0; / compile the pattern (only in the FIRST call scratch-re = pcre_compile(pattern, 0 /* default options */, &scratch-error, &scratch-errOffset, NULL); if (scratch-re = NULL) snprintf(SQLUDF_MSGTX, 70, Regexp compilation failed at offset %d: %sn, scratch-errOffset, scratch-error); strcpy(SQLUDF_STATE, 38900); rc = -1; break; / further analyze the pattern (might return NULL) scratch-extra = pcre_study(scratch-re, 0 /* default options */, &scratch-error); /* fall through to NORMAL call because DB2 expects a result already in the FIRST call */ case SQLUDF_NORMAL_CALL: / match the current string rc = pcre_exec(scratch-re, scratch-extra, str-data, str-length, 0, 0 /* default options */, NULL, 0); switch (rc) case PCRE_ERROR_NOMATCH: *match = 0; rc = 0; break; case PCRE_ERROR_BADOPTION: snprintf(SQLUDF_MSGTX, 70, An unrecognized bit was set in the options argument); strcpy(SQLUDF_STATE, 38901); rc = -1; break; case PCRE_ERROR_NOMEMORY: snprintf(SQLUDF_MSGTX, 70, Not enough memory available.); strcpy(SQLUDF_STATE, 38902); rc = -1; break; default: if (rc 0) snprintf(SQLUDF_MSGTX, 70, A regexp match error occured: %d, rc); strcpy(SQLUDF_STATE, 38903); rc = -1; else *match = 1; rc = 0; break; break; / cleanup in FINAL call, or if we encountered an error in / the FIRST call (DB2 will make a FINAL call if we encounter / an error in any NORMAL call) if (SQLUDF_CALLT = SQLUDF_FINAL_CALL | (SQLUDF_CALLT = SQLUDF_FIRST_CALL & rc re); (*pcre_free)(scratch-extra); return; 为了进一步改进该函数的性能,我添加了对函数 pcre_study() 的调用,该函数是由模式匹配引擎提供的。该函数进一步分析了该模式,并将额外的信息存储在独立的结构中。然后,在实际的匹配期间使用这些额外的信息来加快处理速度。通过使用一个非常简单的模式和大约 4000 行的表,我获得了 5% 的执行时间的改善。当然,模式越复杂,差异将越显著。DB2中实现正则表达式(3) 2005-12-01 10:00 出处:IBM中国 【导读】本文简略地介绍了正则表达式以及 DB2 中可用的字符串比较和匹配功能。还描述了为什么正则表达式的强大功能是如此有用。 先前提到该实现假定模式在处理期间不会随行的不同而更改。当然,如果模式确实更改了,您可以进行少量的改写以再次编译一个模式。要这样做,有必要跟踪当前(已编译的)模式并在每次调用中将它与所提供的模式进行比较。也可以在高速暂存中维护当前模式。但必须将它复制到独立的缓冲区,并且不能通过指针模式直接引用它,因为这个指针或它所引用的数据可能会更改或变为无效。至于相应的代码更改,就当作练习留给读者了。返回匹配子串大多数模式匹配引擎提供了一种方法,返回与指定模式或其一部分相匹配的子串。如果想在 SQL 中使用这种能力,则必须使用不同的方法来实现匹配函数。给定的字符串可能包含不止一个匹配的子串。例如,当解析类似“abc = 123;”或“def = some text;”这样的字符串时,用户可能会希望检索由等号分隔的两个子串。您可以使用模式“w+s*=s*(d+|ws *);”来表示适用于该字符串的语法规则。Perl 兼容的正则表达式允许您捕获等号两边的子串。最后,必须将要捕获的子串用括号括起来。我已经用该方式编写了第二个子串,但第一个子串不是这样编写的。用于该用途的最终模式是这样的:(w+)s*=s*(d+|ws*); 当把这个模式应用于字符串“abc= 123;”或“def = some text;”时,“abc”或“def”分别与“(w+)”匹配,空格和等号是通过“s*=s*”查找的,并用另外的“(d+| ws*)”涵盖了余下的子串。在“(d+|ws*)”中,第一个选项与任何至少由一个数字“d+”组成的数匹配,而第二个选项解析任何由字母和空格组成的由单引号括起的字符串“ws*”。在 DB2 中做到这一点的需求可以描述成:为一次 UDF 调用返回多个结果。换句话说,就是返回针对模式进行匹配的单个字符串的多个子串。DB2 的表函数是完成这一任务的完美工具。实现表 UDF和以前一样,必须在数据库中创建该函数。 清单 8中的下列语句正是用于这一任务的: 清单 8. 注册名为 regex3 的表 UDF CREATE FUNCTION regex3(pattern VARCHAR(2048), string CLOB(10M) RETURNS TABLE ( position INTEGER, substring VARCHAR(2048) ) SPECIFIC regexSubstr EXTERNAL NAME regexUdf!regexpSubstr LANGUAGE C PARAMETER STYLE DB2SQL DETERMINISTIC NOT FENCED RETURNS NULL ON NULL INPUT NO SQL NO EXTERNAL ACTION SCRATCHPAD 50 NO FINAL CALL DISALLOW PARALLEL; 实现该函数的实际逻辑的 C 代码与 清单 7中的代码非常相似,但根据表函数所必须满足的特殊需求对它进行了改编,如 清单 9所示。DB2中实现正则表达式(4) 2005-12-01 10:00 出处:IBM中国 【导读】本文简略地介绍了正则表达式以及 DB2 中可用的字符串比较和匹配功能。还描述了为什么正则表达式的强大功能是如此有用。 清单 9. 实现表函数将要使用的 regex3 函数 #include #include #include #include struct scratchPadMapping pcre *re; pcre_extra *extra; const char *error; int errOffset; int numSubstr; int *substr; int currentSubstr;void regexpSubstr( / input parameters SQLUDF_VARCHAR *pattern, SQLUDF_CLOB *str, / output SQLUDF_INTEGER *pos, SQLUDF_VARCHAR *substr, / null indicators SQLUDF_NULLIND *pattern_ind, SQLUDF_NULLIND *str_ind, SQLUDF_NULLIND *pos_ind, SQLUDF_NULLIND *substr_ind, SQLUDF_TRAIL_ARGS_ALL) / SQLUDF_SCRAT & SQLUDF_CALLT int rc = 0; size_t length = 0; struct scratchPadMapping *scratch = NULL; / map the buffer of the scratchpad and assume NULL return scratch = (struct scratchPadMapping *)SQLUDF_SCRAT-data; *pos_ind = 0; *substr_ind = 0; switch (SQLUDF_CALLT) case SQLUDF_TF_OPEN: / initialize data on the scratchpad scratch-re = NULL; scratch-extra = NULL; scratch-error = NULL; scratch-errOffset = 0; scratch-numSubstr = 0; scratch-substr = NULL; scratch-currentSubstr = 1; / skip the complete match / compile the pattern (only in the FIRST call scratch-re = pcre_compile(pattern, 0 /* default options */, &scratch-error, &scratch-errOffset, NULL); if (scratch-re = NULL) snprintf(SQLUDF_MSGTX, 70, Regexp compilation failed at offset %d: %sn, scratch-errOffset, scratch-error); strcpy(SQLUDF_STATE, 38900); rc = -1; break; / further analyze the pattern (might return NULL) scratch-extra = pcre_study(scratch-re, 0 /* default options */, &scratch-error); / determine the number of capturing subpatterns rc = pcre_fullinfo(scratch-re, scratch-extra, PCRE_INFO_CAPTURECOUNT, &scratch-numSubstr); if (rc) snprintf(SQLUDF_MSGTX, 70, Could not retrieve info on pattern. (rc = %d), rc); strcpy(SQLUDF_STATE, 38901); rc = -1; break; / allocate memory for the substring indices int size = (scratch-numSubstr+1)*3; scratch-substr = (int *)malloc(size * sizeof(int); if (!scratch-substr) snprintf(SQLUDF_MSGTX, 70, Could allocate memory for substring indices.); strcpy(SQLUDF_STATE, 38902); rc = -1; break; memset(scratch-substr, 0, size * sizeof(int); / match the current string rc = pcre_exec(scratch-re, scratch-extra, str-data, str-length, 0, 0 /* default options */, scratch-substr, size); switch (rc) case PCRE_ERROR_BADOPTION: snprintf(SQLUDF_MSGTX, 70, An unrecognized bit was set in the options argument); strcpy(SQLUDF_STATE, 38903); rc = -1; break; case PCRE_ERROR_NOMEMORY: snprintf(SQLUDF_MSGTX, 70, Not enough memory available.); strcpy(SQLUDF_STATE, 38904); rc = -1; break; case PCRE_ERROR_NOMATCH: scratch-currentSubstr = scratch-numSubstr + 1; rc = 0; break; default: if (rc currentSubstr numSubstr & (scratch-substr2*scratch-currentSubstr substr2*scratch-currentSubstr+1 currentSubstr+; / no more data to be returned if (scratch-currentSubstr scratch-numSubstr) strcpy(SQLUDF_STATE, SQL_NODATA_EXCEPTION); rc = 0; break; / get the current substring *pos = scratch-currentSubstr; length = scratch-substr2*scratch-currentSubstr+1 - scratch-substr2*scratch-currentSubstr; strncpy(substr, str-data + scratch-substr2*scratch-currentSubstr, length); substrlength = 0; scratch-currentSubstr+; / cleanup in CLOSE call, or if we encountered an error in / the OPEN call (DB2 will make a CLOSE call if we encounter / an error in any FETCH call) if (SQLUDF_CALLT = SQLUDF_TF_CLOSE | (SQLUDF_CALLT = SQLUDF_TF_OPEN & rc re); (*pcre_free)(scratch-extra); free(scratch-substr); retu
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- GB/T 41762.1-2025纤维增强塑料复合材料层合板厚度方向性能的测定第1部分:直接拉伸和压缩试验
- 起重指挥考试题库及答案
- 森林火灾防治知识培训课件
- 森林消防扑灭火课件
- 桥梁预算编制课件
- 桥梁行车安全知识培训课件
- 风湿免疫科医师应聘试题试卷(临床专业)含答案
- 2025主管护师冲刺试题专业知识题目附答案
- 2025年气排球裁判试题库及答案
- 桥梁基础及下部结构
- 《海上风电场工程测量规程》(NB-T 10104-2018)
- 物业保安、保洁项目投标书
- 2022智慧建筑评价标准
- 《危险化学品目录(2022调整版)》
- 高中信息技术开学第一课课件
- 【公开课】北师大版四年级上册数学《乘法分配律说课》课件
- 广东省义务教育阶段学生转学申请表
- 挫折是成长的必修课主题教育PPT模板
- 网络摄像机-模组接口规格书精简板
- 社工政策与法规
- 绿茶多酚及超级灵芝萃取物与预防癌症之关系博士
评论
0/150
提交评论