DB2中实现正则表达式.docx

上传人:b****8 文档编号:28227408 上传时间:2023-07-09 格式:DOCX 页数:23 大小:24.11KB
下载 相关 举报
DB2中实现正则表达式.docx_第1页
第1页 / 共23页
DB2中实现正则表达式.docx_第2页
第2页 / 共23页
DB2中实现正则表达式.docx_第3页
第3页 / 共23页
DB2中实现正则表达式.docx_第4页
第4页 / 共23页
DB2中实现正则表达式.docx_第5页
第5页 / 共23页
点击查看更多>>
下载资源
资源描述

DB2中实现正则表达式.docx

《DB2中实现正则表达式.docx》由会员分享,可在线阅读,更多相关《DB2中实现正则表达式.docx(23页珍藏版)》请在冰豆网上搜索。

DB2中实现正则表达式.docx

DB2中实现正则表达式

DB2中实现正则表达式

(1)

2005-12-0110:

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匹配模式

SELECTstr

FROMstrTable

WHERE(strLIKE'%=0;%'ORstrLIKE'%=1;%'ORstrLIKE'%=2;%'

ORstrLIKE'%=3;%'ORstrLIKE'%=4;%'ORstrLIKE'%=5;%'

ORstrLIKE'%=7;%'ORstrLIKE'%=7;%'ORstrLIKE'%=8;%'

ORstrLIKE'%=9;%'ORstrLIKE'%=0x00;%')

这增加了可以匹配“[A-Z]*”子模式的谓词的复杂度,这可以使用对整个字符串进行迭代并进行逐字符比较的函数来完成,但您会发现使用内置功能既冗长又复杂。

示例方案

让我们定义下列清单(清单2)并插入几行:

清单2.创建我们的样本表

CREATETABLEstrTable(c1INTEGER,strVARCHAR(500));

INSERTINTOstrTableVALUES(1,'sometext;'),

(2,'variable=1234;'),

(3,'var2=''stringvariable'';'),

(4,'xyz='),

(5,'myVar=0x00;'),

(6,'#comment'),

(7,'abc=def');

这个清单及其数据被用于下面的所有示例。

SELECT*FROMstrTable;

C1STR

-----------------------------------------

1sometext;

2variable=1234;

3var2='stringvariable';

4xyz=

5myVar=0x00;

6#comment

7abc=def

7record(s)selected.

实现模式匹配函数

您可以使用DB2的可扩展机制,在SQL语句内使用UDF,以便显著地改善这种情形。

通过定义名为regex1的UDF(它采用模式和字符串作为输入参数),清单1中的WHERE子句现在可以写得象清单3中所示的那样:

清单3.使用regexUDF来简化模式匹配

SELECTstr

FROMstrTable

WHEREregex1('\\w*=(\\d|0x00);',str)=1

在本示例中,使用带有Perl扩展的正则表达式来匹配完整的模式,而不仅仅是清单1中给出的LIKE谓词所对应的部分模式。

正如您所看到的,使用函数来为该模式编写谓词比用LIKE谓词表示同样的语义要容易得多。

实现UDF

在我的示例实现中,我选择了现有的名为PCRE(Perl兼容的正则表达式,Perl-compatibleregularexpression)的模式匹配引擎。

该引擎提供了用来处理模式和执行匹配的CAPI。

该引擎和查询中所用的SQL语言之间“缺失的部分”是UDF。

该UDF由两部分组成:

在数据库中创建(或注册)该函数的CREATEFUNCTION语句。

该函数的主体,它实现了用于正则表达式匹配引擎的CAPI调用的封装器

清单4显示了用于创建该函数的SQL语句。

清单4.注册regex1函数

CREATEFUNCTIONregex1(patternVARCHAR(2048),stringCLOB(10M))

RETURNSINTEGER

SPECIFICregexSimple

EXTERNALNAME'regexUdf!

regexpSimple'

LANGUAGEC

PARAMETERSTYLEDB2SQL

DETERMINISTIC

NOTFENCED

RETURNSNULLONNULLINPUT

NOSQL

NOEXTERNALACTION

ALLOWPARALLEL;

注:

请参阅DB2SQLReference以获取所有子句的详细含义。

可以修改参数的长度以适应您的需求。

我在此处展示某些值并没有任何推荐使用它们的用意。

DB2中实现正则表达式

(2)

2005-12-0110:

00出处:

IBM中国

【导读】本文简略地介绍了正则表达式以及DB2中可用的字符串比较和匹配功能。

还描述了为什么正则表达式的强大功能是如此有用。

第二部分由一小段C代码组成,它实现了UDF入口点。

在查询执行期间,DB2为每个要与模式匹配的行调用这个入口点。

清单5中的示例列出了该代码的清单。

有关pcre_*函数和宏的描述,请参考PCRE库的文档。

有关C代码的编译和共享库的构建,请参考DB2ApplicationDevelopmentGuide。

清单5.实现rege1xUDF入口点的C代码

#include

#include

voidregexpSimple(

//inputparameters

SQLUDF_VARCHAR*pattern,SQLUDF_CLOB*str,

//output

SQLUDF_INTEGER*match,

//nullindicators

SQLUDF_NULLIND*pattern_ind,SQLUDF_NULLIND*str_ind,

SQLUDF_NULLIND*match_ind,

SQLUDF_TRAIL_ARGS)

{

pcre*re=NULL;

constchar*error=NULL;

interrOffset=0;

intrc=0;

//weassumesuccessfulreturn

*match_ind=0;

//compilethepatterntoitsinternalrepresentation

re=pcre_compile(pattern,0/*defaultoptions*/,&error,

&errOffset,NULL);

if(re==NULL){

snprintf(SQLUDF_MSGTX,70,"Regexpcompilationfailedat"

"offset%d:

%s\\n",errOffset,error);

strcpy(SQLUDF_STATE,"38900");

(*pcre_free)(re);

return;

}

//matchthestringagaintsthepattern

rc=pcre_exec(re,NULL,str->data,str->length,0,

0/*defaultoptions*/,NULL,0);

switch(rc){

casePCRE_ERROR_NOMATCH:

*match=0;

break;

casePCRE_ERROR_BADOPTION:

snprintf(SQLUDF_MSGTX,70,"Anunrecognizedbitwassetinthe"

"optionsargument");

strcpy(SQLUDF_STATE,"38901");

break;

casePCRE_ERROR_NOMEMORY:

snprintf(SQLUDF_MSGTX,70,"Notenoughmemoryavailable.");

strcpy(SQLUDF_STATE,"38902");

break;

default:

if(rc<0){

snprintf(SQLUDF_MSGTX,70,"Aregexpmatcherror"

"occured:

%d",rc);

strcpy(SQLUDF_STATE,"38903");

}

else{

*match=1;

}

break;

}

//cleanup

(*pcre_free)(re);

return;

}

用法示例

下列查询试图从表strTable中找出包含注释文本的所有字符串。

注释以“#”开头,所以模式是“#”后跟非空文本。

SELECTc1,str

FROMstrTable

WHEREregex1('#\\s*\\w+',str)=1;

结果只包含c1=6的行。

C1STR

------------------------------------

6#comment;

1record(s)selected.

在第二个示例中,我们试图找到这种赋值形式的字符串;即“text=text”。

为了进一步缩小范围,我们只查找那些右端为数值的赋值。

将十六进制表示法作为有效数值对待。

SELECTc1,str

FROMstrTable

WHEREregex1('\\w+\\s*=\\s*(\\d+|0x\\d\\d)',str)=1;

除了c1为2或5的两行以外,其它行都不包含数值的赋值,因此不会出现在结果中:

C1STR

------------------------------------

2variable=1234;

5myVar=0x00;

2record(s)selected.

改进性能

尽管上面的函数按照预期的方式工作,但还可以改进它以获得更佳的性能。

注:

函数内部的执行完成得越快,DB2处理整个SQL语句的速度也就越快。

SQL旨在处理多组行,这意味着通常会针对一个模式匹配多个行。

在大多数情况下,模式本身对于整个SQL语句都是不变的;即,它不会随行的更改而更改。

清单5中的C代码展示了对每一行都调用函数pcre_compile(),该函数将给定模式转换成内部表示法。

DB2通过使用所谓的“高速暂存(scratchpad)”提供了在UDF调用之间传递信息的机制。

此外,您可以标识特定调用“类型”;即它是对该UDF的第一次调用、普通调用还是最后一次(最终)调用。

使用高速暂存和调用类型,有可能只对模式编译一次,然后将该已编译模式的内部表示法重用于对该UDF的所有后续调用。

在最后一次调用时,释放在处理期间分配的资源。

如清单6所示,对CREATEFUNCTION语句进行修改,告诉DB2向外部C代码提供高速暂存和调用类型:

清单6.将高速暂存和调用类型添加到CREATEFUNCTION语句

CREATEFUNCTIONregex2(patternVARCHAR(2048),stringCLOB(10M))

RETURNSINTEGER

SPECIFICregexPerf

EXTERNALNAME'regexUdf!

regexpPerf'

LANGUAGEC

PARAMETERSTYLEDB2SQL

DETERMINISTIC

NOTFENCED

RETURNSNULLONNULLINPUT

NOSQL

NOEXTERNALACTION

SCRATCHPAD50

FINALCALL

ALLOWPARALLEL;

UDF入口点看起来很不一样,因为必须改写函数内部的逻辑。

参数方面唯一的更改是使用SQLUDF_TRAIL_ARGS_ALL代替了SQLUDF_TRAIL_ARGS,如清单7所示。

清单7.regex2的CUDF入口点

#include

#include

//datastructuremappedonthescratchpadforeasieruseandaccess

//totheobjects

//thesizeofthescratchpaddefinedintheCREATEFUNCTIONstatement

//mustbeatleastaslargeassizeof(scratchPadMapping)

structscratchPadMapping{

pcre*re;

pcre_extra*extra;

constchar*error;

interrOffset;

};

voidregexpPerf(

//inputparameters

SQLUDF_VARCHAR*pattern,SQLUDF_CLOB*str,

//output

SQLUDF_INTEGER*match,

//nullindicators

SQLUDF_NULLIND*pattern_ind,SQLUDF_NULLIND*str_ind,

SQLUDF_NULLIND*match_ind,

SQLUDF_TRAIL_ARGS_ALL)//SQLUDF_SCRAT&SQLUDF_CALLT

{

intrc=0;

structscratchPadMapping*scratch=NULL;

//mapthebufferofthescratchpadandassumesuccessfulreturn

scratch=(structscratchPadMapping*)SQLUDF_SCRAT->data;

*match_ind=0;

switch(SQLUDF_CALLT){

caseSQLUDF_FIRST_CALL:

//initializedataonthescratchpad

scratch->re=NULL;

scratch->extra=NULL;

scratch->error=NULL;

scratch->errOffset=0;

//compilethepattern(onlyintheFIRSTcall

scratch->re=pcre_compile(pattern,0/*defaultoptions*/,

&scratch->error,&scratch->errOffset,NULL);

if(scratch->re==NULL){

snprintf(SQLUDF_MSGTX,70,"Regexpcompilationfailedat"

"offset%d:

%s\\n",scratch->errOffset,scratch->error);

strcpy(SQLUDF_STATE,"38900");

rc=-1;

break;

}

//furtheranalyzethepattern(mightreturnNULL)

scratch->extra=pcre_study(scratch->re,

0/*defaultoptions*/,&scratch->error);

/*fallthroughtoNORMALcallbecauseDB2expectsaresult

alreadyintheFIRSTcall*/

caseSQLUDF_NORMAL_CALL:

//matchthecurrentstring

rc=pcre_exec(scratch->re,scratch->extra,str->data,

str->length,0,0/*defaultoptions*/,NULL,0);

switch(rc){

casePCRE_ERROR_NOMATCH:

*match=0;

rc=0;

break;

casePCRE_ERROR_BADOPTION:

snprintf(SQLUDF_MSGTX,70,"Anunrecognizedbitwasset"

"intheoptionsargument");

strcpy(SQLUDF_STATE,"38901");

rc=-1;

break;

casePCRE_ERROR_NOMEMORY:

snprintf(SQLUDF_MSGTX,70,"Notenoughmemoryavailable.");

strcpy(SQLUDF_STATE,"38902");

rc=-1;

break;

default:

if(rc<0){

snprintf(SQLUDF_MSGTX,70,"Aregexpmatcherror"

"occured:

%d",rc);

strcpy(SQLUDF_STATE,"38903");

rc=-1;

}

else{

*match=1;

rc=0;

}

break;

}

break;

}

//cleanupinFINALcall,orifweencounteredanerrorin

//theFIRSTcall(DB2willmakeaFINALcallifweencounter

//anerrorinanyNORMALcall)

if(SQLUDF_CALLT==SQLUDF_FINAL_CALL||

(SQLUDF_CALLT==SQLUDF_FIRST_CALL&&rc<0)){

(*pcre_free)(scratch->re);

(*pcre_free)(scratch->extra);

}

return;

}

为了进一步改进该函数的性能,我添加了对函数pcre_study()的调用,该函数是由模式匹配引擎提供的。

该函数进一步分析了该模式,并将额外的信息存储在独立的结构中。

然后,在实际的匹配期间使用这些额外的信息来加快处理速度。

通过使用一个非常简单的模式和大约4000行的表,我获得了5%的执行时间的改善。

当然,模式越复杂,差异将越显著。

DB2中实现正则表达式(3)

2005-12-0110:

00出处:

IBM中国

【导读】本文简略地介绍了正则表达式以及DB2中可用的字符串比较和匹配功能。

还描述了为什么正则表达式的强大功能是如此有用。

先前提到该实现假定模式在处理期间不会随行的不同而更改。

当然,如果模式确实更改了,您可以进行少量的改写以再次编译一个模式。

要这样做,有必要跟踪当前(已编译的)模式并在每次调用中将它与所提供的模式进行比较。

也可以在高速暂存中维护当前模式。

但必须将它复制到独立的缓冲区,并且不能通过指针模式直接引用它,因为这个指针或它所引用的数据可能会更改或变为无效。

至于相应的代码更改,就当作练习留给读者了。

返回匹配子串

大多数模式匹配引擎提供了一种方法,返回与指定模式或其一部分相匹配的子串。

如果想在SQL中使用这种能力,则必须使用不同的方法来实现匹配函数。

给定的字符串可能包含不止一个匹配的子串。

例如,当解析类似“abc=123;”或“def='sometext';”这样的字符串时,用户可能会希望检索由等号分隔的两个子串。

您可以使用模式“\\w+\\s*=\\s*(\\d+|'[\\w\\s]*');”来表示适用于该字符串的语法规则。

Perl兼容的正则表达式允许您捕

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 成人教育 > 自考

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1