第六章 疯狂Caché 正则表达式(二)

第六章 疯狂Caché 正则表达式(二)

逻辑运算符

可以通过将值与逻辑AND(&&)、逻辑OR(|)和减法(--)运算符组合来表示复合字符类型。复合字符类型必须用方括号括起来。

隐式OR:可以使用不带逻辑运算符的方括号来指定匹配字符的列表或范围,其中一个必须为TRUE。以下示例匹配所有大写字母和数字1234[\p{LU}1234]或 [[:upper:]1234], [\p{LU}1-4][[:upper:]1-4].

AND(&&):可以使用逻辑AND指定多个字符类型元字符,这两个字符类型都必须为true。例如,要将匹配限制为仅大写希腊字母,可以指定[\p{LU}&&\p{greek}][[:upper:]&&[:greek:]].

OR(|):可以使用逻辑OR指定多个字符类型元字符,其中任何一个必须为真。例如,要将匹配限制为数字或希腊字母,可以指定:[\p{N}|\p{greek}][[:digit:]|[:greek:]]。请注意,这种显式OR的使用是可选的;没有逻辑运算符的字符类型列表被解释为逻辑OR。

减法(--):可以使用逻辑减法指定多个字符类型元字符,第一个必须为TRUE,第二个必须为FALSE。例如,要限制匹配除希腊字母之外的所有大写字母,可以指定[\p{LU}--\p{greek}][[:upper:]--[:greek:]]

字符表示元字符

以下是各个字符的元字符表示形式。每个序列与单个字符匹配。

请注意,一些单独的控制字符($CHAR(7)$CHAR(9)$CHAR(10)$CHAR(12)$CHAR(13)$CHAR(27))也可以使用单字母字符类型表示。

十六进制、八进制和Unicode表示法

  • \xnn\x{nnn} 十六进制表示法。例如,\x5A是字母Z”。请注意,十六进制字母A到F不区分大小写。可以包括或省略前导零。\xnn可用于一位或两位十六进制数。对于位数较多的十六进制数字,必须使用\x{nnn}大括号语法,其中nnn可以是1到7个十六进制数字,最大值为010FFFF。例如,\x{005A}是字母‘Z’,\x{396}是希腊字母Zeta

  • \0nnn 八进制表示法。nnn值是两位、三位或四位的八进制值;但是,最左边的数字必须是零。例如,回车符$CHAR(13)可以由\015\0015表示。最大值为\0377,即$CHAR(255)

-\unnnn Unicode表示形式。nnnn值是与Unicode字符对应的四位十六进制数。例如,\u005A是字母‘Z’($Char(90)\u03BB是希腊文小写lambda($Char(955))。

/// d ##class(PHA.TEST.ObjectScript).TestChinese("是多少")
ClassMethod TestChinese(input)
{
	
	IF 1=$MATCH(input,"[\u4e00-\u9fa5]+") {
		w "是中文",!
	}else{
		w "不是中文",!
	}
}
DHC-APP>d ##class(PHA.TEST.ObjectScript).TestChinese("是多少")
是中文

控制字符表示法

控制字符是非打印ASCII字符$CHAR(0)$CHAR(31)。它们可以使用以下语法表示:

\cX

其中X是对应于ASCII控制字符(字符0到31)的字母或符号。字母对应于$CHAR(1)$CHAR(26)。例如,\CH$CHAR(8),即退格字符。X字母不区分大小写。非字母控制字符遵循相同的ASCII字符集序列,如下所示:$CHAR(0)=\c@\c$CHAR(27)=\c{\c[$CHAR(28)=\c|\c\$CHAR(29)=\c}\c]``,$CHAR(30)=\c^\c~$CHAR(31)=\c_

符号

此字符类型可用于匹配单个可打印的标点符号、空格和符号字符。语法如下:

\N{charname}

例如,\N{逗号}与逗号匹配。请注意,元字符\N必须是大写字母。支持的字符名称包括:重音符号(‘)、与号(&)、撇号(’)、星号(*)、缩写(˘)cedilla(?)、冒号(:)、逗号(,)、匕首(†)、度符号(°)、分号(?)、美元符号($)、双匕首(‡)、破折号(-)、短划线(-)、感叹号(!)、等号(=)。左方括号([)、马克龙(‘)、乘号(×)、加号(+)、井号(#)、素号(’)、问号(?)、右花括号(})、右圆括号()、右方括号(])、分号(;;)、空格()、平方根(√)、波浪号(~)、垂直线(|)。还支持下标0至下标9和上标0至上标9。

模式

模式会更改紧随其后的字符匹配的解释。模式由单个小写字母指定。使用模式有两种方式:

  • 正则表达式序列的模式。例如:(?i)
  • 正则表达式中指定文字的模式。例如:(?i:(fred|ginger))

支持以下模式字符:

  • (?i) 案例模式。处于活动状态时,将大小写字母与正则表达式匹配时忽略字母大小写。
  • (?m) 多行模式。应用于多行字符串时,会影响^(字符串开头)和$(字符串结尾)锚点的行为。默认情况下,这些锚点应用于整个字符串。当多行模式处于活动状态时,这些定位将应用于多行字符串中每行的开头和结尾。行可以由任何换行符开始:10、11、12、13、133(以及Unicode 8232和8233)。
  • (?s) 单行模式。禁用时,点(.)。通配符与换行符10、11、12、13、133(以及Unicode 8232和8233)不匹配。启用时,点(.)。通配符匹配所有字符,包括换行符。请注意,按该顺序指定的字符对回车符($CHAR(13))和换行符($CHAR(10))在正则表达式中被计为单个字符。
  • (?x) 自由间距模式。允许正则表达式中的空格和尾随注释。

正则表达式序列的模式

regexp模式从正则表达式应用到正则表达式的末尾开始,或直到显式关闭为止,控制正则表达式解释。语法如下:

(?n)  to turn mode on
(?-n) to turn mode off

其中n是指定模式类型的单个小写字母。

以下示例显示案例模式(?i)

  WRITE $MATCH("A","(?i)[abc]"),!
  WRITE $MATCH("a","(?i)[abc]")
1

以下示例显示案例模式(?i)。第一个正则表达式区分大小写。第二个正则表达式以大小写模式修饰符(?i)开头,使正则表达式不区分大小写:

  SET name(1)="Smith,John"
  SET name(2)="dePaul,Lucius"
  SET name(3)="smith,john"
  SET name(4)="John Smith"
  SET name(5)="Smith,J"
  SET name(6)="R2D2,CP30"
  SET n=1
  WHILE $DATA(name(n)) {
    IF $MATCH(name(n),"\p{LU}\p{LL}+,\p{LU}\p{LL}+")
      { WRITE name(n)," : case match",! }
    ELSEIF $MATCH(name(n),"(?i)\p{LU}\p{LL}+,\p{LU}\p{LL}+")
      { WRITE name(n)," : non-case match",! }
    ELSE { WRITE name(n)," : not a valid name",! }
    SET n=n+1 }
Smith,John : case match
dePaul,Lucius : non-case match
smith,john : non-case match
John Smith : not a valid name
Smith,J : not a valid name
R2D2,CP30 : not a valid name

以下示例显示单行模式(?s),该模式允许“.*”匹配包含换行符的字符串:

  SET line(1)="This is a string without line breaks."
  SET line(2)="This is a string with"_$CHAR(10)_"one line break."
  SET line(3)="This is a string"_$CHAR(11)_"with"_$CHAR(12)_"two line breaks."
  SET i=1
  WHILE $DATA(line(i)) {
    IF $MATCH(line(i),".*") {WRITE "line(",i,") is a single line string",! }
    ELSEIF $MATCH(line(i),"(?s).*") {WRITE "line(",i,") is a multiline string",! }
    ELSE {WRITE "string error",! }
    SET i=i+1 } 
line(1) is a single line string
line(2) is a multiline string
line(3) is a multiline string

以下示例以单行模式(?s)显示正则表达式中的回车/换行符对(按该顺序)被计为一个字符:

  SET str(1)="one"_$CHAR(13)_$CHAR(10)_"two"   // CR/LF
  SET str(2)="one"_$CHAR(10)_$CHAR(13)_"two"   // LF/CR
  SET i=1
  WHILE $DATA(str(i)) {
     WRITE $LENGTH(str(i))," is the length of string ",i,!
     IF $MATCH(str(i),"(?s).{7}") { WRITE "string ",i," matches 7 chars",! }
     ELSEIF $MATCH(str(i),"(?s).{8}") { WRITE "string ",i," matches 8 chars",! }
     ELSE { WRITE "string match error",! }
     SET i=i+1
   }
8 is the length of string 1
string 1 matches 7 chars
8 is the length of string 2
string 2 matches 8 chars

以下示例显示多行模式(?m)。它定位由结束锚点($)标识的子字符串。在单行模式下,此结束子字符串始终为“Break”,即字符串中的最后一个子字符串。在多行模式下,结束子字符串可以是多行字符串中结束一行的任意子字符串:

  SET line(1)="String without line break"
  SET line(2)="String with"_$CHAR(10)_" one line break"
  SET line(3)="String"_$CHAR(11)_" with"_$CHAR(12)_" two line break"
  SET i=1
  WHILE $DATA(line(i)) {
    WRITE $LOCATE(line(i),"(String|with|break)$")," line(",i,") in single-line mode",! 
    WRITE $LOCATE(line(i),"(?m)(String|with|break)$")," line(",i,") in multi-line mode",!!
    SET i=i+1 } 
21 line(1) in single-line mode
21 line(1) in multi-line mode

23 line(2) in single-line mode
8 line(2) in multi-line mode

24 line(3) in single-line mode
1 line(3) in multi-line mode

文本的模式

还可以使用以下语法将模式修饰符应用于文字(或一组文字):

(?mode:literal)

此模式修改仅适用于括号内的文字。

以下大小写模式(?i)示例匹配以dedeldeladella开头的姓氏(Lname),而不考虑此前缀的大小写。lname的其余部分必须以大写字母开头,后跟至少一个小写字母:

  SET lname(1)="deTour"
  SET lname(2)="DeMarco"
  SET lname(3)="DeLaRenta"
  SET lname(4)="DelCarmine"
  SET lname(5)="dellaRobbia"
  SET i=1
  WHILE $DATA(lname(i)) {
     WRITE $MATCH(lname(i),"(?i:de|del|dela|della)\p{LU}\p{LL}+")," = ",lname(i),!
     SET i=i+1 }

1 = deTour
1 = DeMarco
1 = DeLaRenta
1 = DelCarmine
1 = dellaRobbia

注释

在正则表达式中,可以指定两种类型的注释:

  • 嵌入的注释
  • 行结束注释(仅适用于(?X)模式)

嵌入的注释

可以使用以下语法将嵌入注释包括在正则表达式中:

(?# comment)

以下示例显示在正则表达式中使用注释来记录此格式匹配是针对美国格式日期(MM/DD/YYYY),而不是针对欧洲格式日期(DD/MM/YYYY):

 WRITE $MATCH("04/28/2012","^[01]\d(?# months)/[0123]\d(?# days)/\d\d\d\d$")
1

行结束注释

当自由空格模式(?x)生效时,可以使用以下语法在正则表达式的末尾添加注释:

# comment

下面的示例显示自由空格模式下的结束注释:

   WRITE $MATCH("04/28/2012","^[01]\d/[0123]\d/\d\d\d\d$")," no comment",!
   WRITE $MATCH("04/28/2012","^[01]\d/[0123]\d/\d\d\d\d$# date test")," comment no (?x) mode",!
   WRITE $MATCH("04/28/2012","(?x)^[01]\d/[0123]\d/\d\d\d\d$# date test")," comment in (?x) mode",!
1 no comment
0 comment no (?x) mode
1 comment in (?x) mode

在自由空格模式下,正则表达式中可以包含空格。

错误消息

指定的regexp不正确会生成<REGULAR EXPRESSION>错误,要确定错误类型,可以调用LastStatus()方法,如下例所示:

  TRY {
    WRITE "TRY block:",!
    WRITE $MATCH("A","\p{LU}"),!  // good regexp
    WRITE $MATCH("A","\p{}"),!    // bad regexp
  }
  CATCH exp {
    WRITE !,"CATCH block exception handler:",!
    IF 1=exp.%IsA("%Exception.SystemException") {
      WRITE "System exception",!
      WRITE "Name: ",$ZCVT(exp.Name,"O","HTML"),!
      WRITE "Location: ",exp.Location,!
      WRITE "Code: ",exp.Code,!! }
    ELSE {WRITE "Unexpected exception type",!  RETURN }
    WRITE "%Regex.Matcher status:"
    DO $SYSTEM.Status.DisplayError(##class(%Regex.Matcher).LastStatus())
    RETURN
  } 
TRY block:
1

CATCH block exception handler:
System exception
Name: <REGULAR EXPRESSION>
Location: EXECTemp1COS+4^DocBook.EXECTemp1COS
Code: 27

%Regex.Matcher status:
错误 #8352: 非法参数,例如模式的空字符串

匹配所有字母

/// w ##class(PHA.TEST.ObjectScript).TestCode()
ClassMethod TestCode()
{
	s str = ""
	read "请输入信息:",input,!
	s start = 0
	s len = $l(input)
	f i = 1 : 1 : len d
	.s code = $e(input,i)
	.i 1 = $MATCH(code,"\p{L}")  d
	..s str = str _ code
	q str
}
DHC-APP>w ##class(PHA.TEST.ObjectScript).TestCode()
请输入信息:abcd2015
abcd
DHC-APP>w ##class(PHA.TEST.ObjectScript).TestCode()
请输入信息:AaasdaCCC001551
AaasdaCCC
DHC-APP>w ##class(PHA.TEST.ObjectScript).TestCode()
请输入信息:aaaa-000
aaaa
原创文章 67 获赞 86 访问量 1万+

猜你喜欢

转载自blog.csdn.net/yaoxin521123/article/details/106133783